2011-02-24 Ilya Tikhonovsky <loislo@chromium.org>
[WebKit-https.git] / Source / WebCore / inspector / InspectorAgent.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 "InspectorAgent.h"
32
33 #if ENABLE(INSPECTOR)
34
35 #include "CachedResource.h"
36 #include "CachedResourceLoader.h"
37 #include "Chrome.h"
38 #include "Cookie.h"
39 #include "CookieJar.h"
40 #include "DOMWindow.h"
41 #include "DOMWrapperWorld.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 "FrameLoadRequest.h"
50 #include "FrameLoader.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "GraphicsContext.h"
54 #include "HTMLFrameOwnerElement.h"
55 #include "HTTPHeaderMap.h"
56 #include "HitTestResult.h"
57 #include "InjectedScript.h"
58 #include "InjectedScriptHost.h"
59 #include "InspectorBrowserDebuggerAgent.h"
60 #include "InspectorCSSAgent.h"
61 #include "InspectorClient.h"
62 #include "InspectorConsoleAgent.h"
63 #include "InspectorController.h"
64 #include "InspectorDOMAgent.h"
65 #include "InspectorDebuggerAgent.h"
66 #include "InspectorFrontend.h"
67 #include "InspectorFrontendClient.h"
68 #include "InspectorInstrumentation.h"
69 #include "InspectorProfilerAgent.h"
70 #include "InspectorResourceAgent.h"
71 #include "InspectorRuntimeAgent.h"
72 #include "InspectorState.h"
73 #include "InspectorTimelineAgent.h"
74 #include "InspectorValues.h"
75 #include "InspectorWorkerResource.h"
76 #include "InstrumentingAgents.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 "ScriptArguments.h"
85 #include "ScriptCallStack.h"
86 #include "ScriptFunctionCall.h"
87 #include "ScriptObject.h"
88 #include "ScriptProfile.h"
89 #include "ScriptProfiler.h"
90 #include "ScriptSourceCode.h"
91 #include "ScriptState.h"
92 #include "SecurityOrigin.h"
93 #include "Settings.h"
94 #include "SharedBuffer.h"
95 #include "TextEncoding.h"
96 #include "TextIterator.h"
97 #include "TextRun.h"
98 #include "UserGestureIndicator.h"
99 #include "WindowFeatures.h"
100 #include <wtf/CurrentTime.h>
101 #include <wtf/ListHashSet.h>
102 #include <wtf/RefCounted.h>
103 #include <wtf/StdLibExtras.h>
104 #include <wtf/UnusedParam.h>
105 #include <wtf/text/StringConcatenate.h>
106
107 #if ENABLE(DATABASE)
108 #include "InspectorDatabaseAgent.h"
109 #endif
110
111 #if ENABLE(DOM_STORAGE)
112 #include "InspectorDOMStorageAgent.h"
113 #endif
114
115 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
116 #include "InspectorApplicationCacheAgent.h"
117 #endif
118
119 using namespace std;
120
121 namespace WebCore {
122
123 namespace InspectorAgentState {
124 static const char searchingForNode[] = "searchingForNode";
125 static const char timelineProfilerEnabled[] = "timelineProfilerEnabled";
126 static const char userInitiatedProfiling[] = "userInitiatedProfiling";
127 static const char debuggerEnabled[] = "debuggerEnabled";
128 static const char profilerEnabled[] = "profilerEnabled";
129 }
130
131 static const char scriptsPanelName[] = "scripts";
132 static const char consolePanelName[] = "console";
133 static const char profilesPanelName[] = "profiles";
134
135 InspectorAgent::InspectorAgent(Page* page, InspectorClient* client)
136     : m_inspectedPage(page)
137     , m_client(client)
138     , m_frontend(0)
139     , m_instrumentingAgents(new InstrumentingAgents())
140     , m_injectedScriptHost(InjectedScriptHost::create(this))
141     , m_domAgent(InspectorDOMAgent::create(m_instrumentingAgents.get(), m_injectedScriptHost.get()))
142     , m_cssAgent(new InspectorCSSAgent(m_domAgent.get()))
143 #if ENABLE(DATABASE)
144     , m_databaseAgent(InspectorDatabaseAgent::create(m_instrumentingAgents.get()))
145 #endif
146 #if ENABLE(DOM_STORAGE)
147     , m_domStorageAgent(InspectorDOMStorageAgent::create(m_instrumentingAgents.get()))
148 #endif
149     , m_state(new InspectorState(client))
150     , m_timelineAgent(InspectorTimelineAgent::create(m_instrumentingAgents.get(), m_state.get()))
151     , m_consoleAgent(new InspectorConsoleAgent(m_instrumentingAgents.get(), this, m_state.get(), m_injectedScriptHost.get(), m_domAgent.get()))
152 #if ENABLE(JAVASCRIPT_DEBUGGER)
153     , m_profilerAgent(InspectorProfilerAgent::create(this))
154 #endif
155 {
156     ASSERT_ARG(page, page);
157     ASSERT_ARG(client, client);
158     InspectorInstrumentation::bindInspectorAgent(m_inspectedPage, this);
159 }
160
161 InspectorAgent::~InspectorAgent()
162 {
163     // These should have been cleared in inspectedPageDestroyed().
164     ASSERT(!m_client);
165     ASSERT(!m_inspectedPage);
166     ASSERT(!m_highlightedNode);
167 }
168
169 void InspectorAgent::inspectedPageDestroyed()
170 {
171     if (m_frontend)
172         m_frontend->disconnectFromBackend();
173
174     ErrorString error;
175     hideHighlight(&error);
176
177 #if ENABLE(JAVASCRIPT_DEBUGGER)
178     m_debuggerAgent.clear();
179     m_browserDebuggerAgent.clear();
180 #endif
181
182     ASSERT(m_inspectedPage);
183     InspectorInstrumentation::unbindInspectorAgent(m_inspectedPage);
184     m_inspectedPage = 0;
185
186     releaseFrontendLifetimeAgents();
187     m_injectedScriptHost->disconnectController();
188
189     m_client->inspectorDestroyed();
190     m_client = 0;
191 }
192
193 bool InspectorAgent::searchingForNodeInPage() const
194 {
195     return m_state->getBoolean(InspectorAgentState::searchingForNode);
196 }
197
198 void InspectorAgent::restoreInspectorStateFromCookie(const String& inspectorStateCookie)
199 {
200     m_state->loadFromCookie(inspectorStateCookie);
201
202     m_frontend->frontendReused();
203     m_frontend->inspectedURLChanged(inspectedURL().string());
204     pushDataCollectedOffline();
205
206     m_resourceAgent = InspectorResourceAgent::restore(m_inspectedPage, m_state.get(), m_frontend);
207     m_timelineAgent->restore(m_state.get(), m_frontend);
208
209 #if ENABLE(JAVASCRIPT_DEBUGGER)
210     restoreDebugger(false);
211     restoreProfiler(ProfilerRestoreResetAgent);
212     if (m_state->getBoolean(InspectorAgentState::userInitiatedProfiling))
213         startUserInitiatedProfiling();
214 #endif
215 }
216
217 void InspectorAgent::inspect(Node* node)
218 {
219     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
220         node = node->parentNode();
221     m_nodeToFocus = node;
222
223     if (!m_frontend)
224         return;
225
226     focusNode();
227 }
228
229 void InspectorAgent::focusNode()
230 {
231     if (!enabled())
232         return;
233
234     ASSERT(m_frontend);
235     ASSERT(m_nodeToFocus);
236
237     m_domAgent->inspect(m_nodeToFocus.get());
238     m_nodeToFocus = 0;
239 }
240
241 void InspectorAgent::highlight(ErrorString*, Node* node)
242 {
243     if (!enabled())
244         return;
245     ASSERT_ARG(node, node);
246     m_highlightedNode = node;
247     m_client->highlight(node);
248 }
249
250 void InspectorAgent::highlightDOMNode(ErrorString* error, long nodeId)
251 {
252     Node* node = 0;
253     if (m_domAgent && (node = m_domAgent->nodeForId(nodeId)))
254         highlight(error, node);
255 }
256
257 void InspectorAgent::highlightFrame(ErrorString* error, unsigned long frameId)
258 {
259     Frame* mainFrame = m_inspectedPage->mainFrame();
260     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext(mainFrame)) {
261         if (reinterpret_cast<uintptr_t>(frame) == frameId && frame->ownerElement()) {
262             highlight(error, frame->ownerElement());
263             return;
264         }
265     }
266 }
267
268 void InspectorAgent::hideHighlight(ErrorString*)
269 {
270     if (!enabled())
271         return;
272     m_highlightedNode = 0;
273     m_client->hideHighlight();
274 }
275
276 void InspectorAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
277 {
278     if (!enabled() || !searchingForNodeInPage())
279         return;
280
281     Node* node = result.innerNode();
282     while (node && node->nodeType() == Node::TEXT_NODE)
283         node = node->parentNode();
284     if (node) {
285         ErrorString error;
286         highlight(&error, node);
287     }
288 }
289
290 bool InspectorAgent::handleMousePress()
291 {
292     if (!enabled() || !searchingForNodeInPage())
293         return false;
294
295     if (m_highlightedNode) {
296         RefPtr<Node> node = m_highlightedNode;
297         setSearchingForNode(false);
298         inspect(node.get());
299     }
300     return true;
301 }
302
303 void InspectorAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
304 {
305     if (world != mainThreadNormalWorld())
306         return;
307
308     if (enabled()) {
309         if (m_frontend && frame == m_inspectedPage->mainFrame())
310             m_injectedScriptHost->discardInjectedScripts();
311
312         if (m_scriptsToEvaluateOnLoad.size()) {
313             ScriptState* scriptState = mainWorldScriptState(frame);
314             for (Vector<String>::iterator it = m_scriptsToEvaluateOnLoad.begin();
315                   it != m_scriptsToEvaluateOnLoad.end(); ++it) {
316                 m_injectedScriptHost->injectScript(*it, scriptState);
317             }
318         }
319     }
320
321     if (!m_inspectorExtensionAPI.isEmpty())
322         m_injectedScriptHost->injectScript(m_inspectorExtensionAPI, mainWorldScriptState(frame));
323 }
324
325 void InspectorAgent::setSearchingForNode(bool enabled)
326 {
327     if (searchingForNodeInPage() == enabled)
328         return;
329     m_state->setBoolean(InspectorAgentState::searchingForNode, enabled);
330     if (!enabled) {
331         ErrorString error;
332         hideHighlight(&error);
333     }
334 }
335
336 void InspectorAgent::setSearchingForNode(ErrorString*, bool enabled, bool* newState)
337 {
338     *newState = enabled;
339     setSearchingForNode(enabled);
340 }
341
342 void InspectorAgent::setFrontend(InspectorFrontend* inspectorFrontend)
343 {
344     // We can reconnect to existing front-end -> unmute state.
345     m_state->unmute();
346
347     m_frontend = inspectorFrontend;
348     createFrontendLifetimeAgents();
349
350     m_domAgent->setFrontend(m_frontend);
351     m_consoleAgent->setFrontend(m_frontend);
352     m_timelineAgent->setFrontend(m_frontend);
353 #if ENABLE(DATABASE)
354     m_databaseAgent->setFrontend(m_frontend);
355 #endif
356 #if ENABLE(DOM_STORAGE)
357     m_domStorageAgent->setFrontend(m_frontend);
358 #endif
359     // Initialize Web Inspector title.
360     m_frontend->inspectedURLChanged(inspectedURL().string());
361 }
362
363 void InspectorAgent::disconnectFrontend()
364 {
365     if (!m_frontend)
366         return;
367
368     // Destroying agents would change the state, but we don't want that.
369     // Pre-disconnect state will be used to restore inspector agents.
370     m_state->mute();
371
372     m_frontend = 0;
373
374     ErrorString error;
375 #if ENABLE(JAVASCRIPT_DEBUGGER)
376     // If the window is being closed with the debugger enabled,
377     // remember this state to re-enable debugger on the next window
378     // opening.
379     disableDebugger(&error);
380 #endif
381     setSearchingForNode(false);
382
383     hideHighlight(&error);
384
385 #if ENABLE(JAVASCRIPT_DEBUGGER)
386     m_profilerAgent->setFrontend(0);
387     m_profilerAgent->stopUserInitiatedProfiling(true);
388 #endif
389
390     m_consoleAgent->clearFrontend();
391     m_domAgent->clearFrontend();
392     m_timelineAgent->clearFrontend();
393 #if ENABLE(DATABASE)
394     m_databaseAgent->clearFrontend();
395 #endif
396 #if ENABLE(DOM_STORAGE)
397     m_domStorageAgent->clearFrontend();
398 #endif
399
400     releaseFrontendLifetimeAgents();
401     m_userAgentOverride = "";
402 }
403
404 InspectorResourceAgent* InspectorAgent::resourceAgent()
405 {
406     if (!m_resourceAgent && m_frontend)
407         m_resourceAgent = InspectorResourceAgent::create(m_inspectedPage, m_state.get(), m_frontend);
408     return m_resourceAgent.get();
409 }
410
411 void InspectorAgent::createFrontendLifetimeAgents()
412 {
413     m_runtimeAgent = InspectorRuntimeAgent::create(m_injectedScriptHost.get());
414
415 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
416     m_applicationCacheAgent = new InspectorApplicationCacheAgent(m_inspectedPage->mainFrame()->loader()->documentLoader(), m_frontend);
417 #endif
418 }
419
420 void InspectorAgent::releaseFrontendLifetimeAgents()
421 {
422     m_resourceAgent.clear();
423     m_runtimeAgent.clear();
424 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
425     m_applicationCacheAgent.clear();
426 #endif
427 }
428
429 void InspectorAgent::populateScriptObjects(ErrorString*)
430 {
431     ASSERT(m_frontend);
432     if (!m_frontend)
433         return;
434
435 #if ENABLE(JAVASCRIPT_DEBUGGER)
436     if (m_profilerAgent->enabled())
437         m_frontend->profilerWasEnabled();
438 #endif
439
440     pushDataCollectedOffline();
441
442     if (m_nodeToFocus)
443         focusNode();
444
445     if (!m_showPanelAfterVisible.isEmpty()) {
446         m_frontend->showPanel(m_showPanelAfterVisible);
447         m_showPanelAfterVisible = "";
448     }
449
450     restoreDebugger(true);
451     restoreProfiler(ProfilerRestoreNoAction);
452
453     // Dispatch pending frontend commands
454     for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
455         m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
456     m_pendingEvaluateTestCommands.clear();
457 }
458
459 void InspectorAgent::pushDataCollectedOffline()
460 {
461     m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
462
463 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS)
464     WorkersMap::iterator workersEnd = m_workers.end();
465     for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it) {
466         InspectorWorkerResource* worker = it->second.get();
467         m_frontend->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker());
468     }
469 #endif
470 }
471
472 void InspectorAgent::restoreDebugger(bool eraseStickyBreakpoints)
473 {
474     ASSERT(m_frontend);
475 #if ENABLE(JAVASCRIPT_DEBUGGER)
476     if (m_state->getBoolean(InspectorAgentState::debuggerEnabled))
477         enableDebugger(eraseStickyBreakpoints);
478 #endif
479 }
480
481 void InspectorAgent::restoreProfiler(ProfilerRestoreAction action)
482 {
483     ASSERT(m_frontend);
484 #if ENABLE(JAVASCRIPT_DEBUGGER)
485     m_profilerAgent->setFrontend(m_frontend);
486     if (m_state->getBoolean(InspectorAgentState::profilerEnabled)) {
487         ErrorString error;
488         enableProfiler(&error);
489     }
490     if (action == ProfilerRestoreResetAgent)
491         m_profilerAgent->resetFrontendProfiles();
492 #endif
493 }
494
495 void InspectorAgent::didCommitLoad(DocumentLoader* loader)
496 {
497     if (!enabled())
498         return;
499
500     if (m_resourceAgent)
501         m_resourceAgent->didCommitLoad(loader);
502
503     ASSERT(m_inspectedPage);
504
505     if (loader->frame() == m_inspectedPage->mainFrame()) {
506         if (m_frontend)
507             m_frontend->inspectedURLChanged(loader->url().string());
508
509         m_injectedScriptHost->discardInjectedScripts();
510         m_consoleAgent->reset();
511
512         if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
513             timelineAgent->didCommitLoad();
514
515 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
516         if (m_applicationCacheAgent)
517             m_applicationCacheAgent->didCommitLoad(loader);
518 #endif
519
520 #if ENABLE(JAVASCRIPT_DEBUGGER)
521         if (m_debuggerAgent) {
522             KURL url = inspectedURLWithoutFragment();
523             m_debuggerAgent->inspectedURLChanged(url);
524             if (m_browserDebuggerAgent)
525                 m_browserDebuggerAgent->inspectedURLChanged(url);
526         }
527 #endif
528
529 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
530         m_profilerAgent->stopUserInitiatedProfiling(true);
531         m_profilerAgent->resetState();
532 #endif
533
534         if (m_frontend) {
535             m_frontend->reset();
536             m_domAgent->reset();
537             m_cssAgent->reset();
538         }
539 #if ENABLE(WORKERS)
540         m_workers.clear();
541 #endif
542 #if ENABLE(DATABASE)
543         m_databaseAgent->clearResources();
544 #endif
545 #if ENABLE(DOM_STORAGE)
546         m_domStorageAgent->clearResources();
547 #endif
548         if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent())
549             domAgent->setDocument(m_inspectedPage->mainFrame()->document());
550     }
551 }
552
553 void InspectorAgent::domContentLoadedEventFired(DocumentLoader* loader, const KURL& url)
554 {
555     if (!enabled() || !isMainResourceLoader(loader, url))
556         return;
557
558     if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent())
559         domAgent->mainFrameDOMContentLoaded();
560     if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
561         timelineAgent->didMarkDOMContentEvent();
562     if (m_frontend)
563         m_frontend->domContentEventFired(currentTime());
564 }
565
566 void InspectorAgent::loadEventFired(DocumentLoader* loader, const KURL& url)
567 {
568     if (!enabled())
569         return;
570
571     if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent())
572         domAgent->loadEventFired(loader->frame()->document());
573
574     if (!isMainResourceLoader(loader, url))
575         return;
576
577     if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
578         timelineAgent->didMarkLoadEvent();
579     if (m_frontend)
580         m_frontend->loadEventFired(currentTime());
581 }
582
583 bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
584 {
585     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
586 }
587
588 void InspectorAgent::setUserAgentOverride(ErrorString*, const String& userAgent)
589 {
590     m_userAgentOverride = userAgent;
591 }
592
593 void InspectorAgent::applyUserAgentOverride(String* userAgent) const
594 {
595     if (!m_userAgentOverride.isEmpty())
596         *userAgent = m_userAgentOverride;
597 }
598
599 #if ENABLE(WORKERS)
600 class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task {
601 public:
602     static PassOwnPtr<PostWorkerNotificationToFrontendTask> create(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
603     {
604         return new PostWorkerNotificationToFrontendTask(worker, action);
605     }
606
607 private:
608     PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
609         : m_worker(worker)
610         , m_action(action)
611     {
612     }
613
614     virtual void performTask(ScriptExecutionContext* scriptContext)
615     {
616         if (scriptContext->isDocument()) {
617             if (InspectorAgent* inspectorAgent = static_cast<Document*>(scriptContext)->page()->inspectorController()->m_inspectorAgent.get())
618                 inspectorAgent->postWorkerNotificationToFrontend(*m_worker, m_action);
619         }
620     }
621
622 private:
623     RefPtr<InspectorWorkerResource> m_worker;
624     InspectorAgent::WorkerAction m_action;
625 };
626
627 void InspectorAgent::postWorkerNotificationToFrontend(const InspectorWorkerResource& worker, InspectorAgent::WorkerAction action)
628 {
629     if (!m_frontend)
630         return;
631 #if ENABLE(JAVASCRIPT_DEBUGGER)
632     switch (action) {
633     case InspectorAgent::WorkerCreated:
634         m_frontend->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker());
635         break;
636     case InspectorAgent::WorkerDestroyed:
637         m_frontend->didDestroyWorker(worker.id());
638         break;
639     }
640 #endif
641 }
642
643 void InspectorAgent::didCreateWorker(intptr_t id, const String& url, bool isSharedWorker)
644 {
645     if (!enabled())
646         return;
647
648     RefPtr<InspectorWorkerResource> workerResource(InspectorWorkerResource::create(id, url, isSharedWorker));
649     m_workers.set(id, workerResource);
650     if (m_inspectedPage && m_frontend)
651         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource, InspectorAgent::WorkerCreated));
652 }
653
654 void InspectorAgent::didDestroyWorker(intptr_t id)
655 {
656     if (!enabled())
657         return;
658
659     WorkersMap::iterator workerResource = m_workers.find(id);
660     if (workerResource == m_workers.end())
661         return;
662     if (m_inspectedPage && m_frontend)
663         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource->second, InspectorAgent::WorkerDestroyed));
664     m_workers.remove(workerResource);
665 }
666 #endif // ENABLE(WORKERS)
667
668 void InspectorAgent::getCookies(ErrorString*, RefPtr<InspectorArray>* cookies, WTF::String* cookiesString)
669 {
670     // If we can get raw cookies.
671     ListHashSet<Cookie> rawCookiesList;
672
673     // If we can't get raw cookies - fall back to String representation
674     String stringCookiesList;
675
676     // Return value to getRawCookies should be the same for every call because
677     // the return value is platform/network backend specific, and the call will
678     // always return the same true/false value.
679     bool rawCookiesImplemented = false;
680
681     for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) {
682         Document* document = frame->document();
683         const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
684         CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
685         for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
686             Vector<Cookie> docCookiesList;
687             rawCookiesImplemented = getRawCookies(document, KURL(ParsedURLString, it->second->url()), docCookiesList);
688
689             if (!rawCookiesImplemented) {
690                 // FIXME: We need duplication checking for the String representation of cookies.
691                 ExceptionCode ec = 0;
692                 stringCookiesList += document->cookie(ec);
693                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
694                 // because "document" is the document of the main frame of the page.
695                 ASSERT(!ec);
696             } else {
697                 int cookiesSize = docCookiesList.size();
698                 for (int i = 0; i < cookiesSize; i++) {
699                     if (!rawCookiesList.contains(docCookiesList[i]))
700                         rawCookiesList.add(docCookiesList[i]);
701                 }
702             }
703         }
704     }
705
706     if (rawCookiesImplemented)
707         *cookies = buildArrayForCookies(rawCookiesList);
708     else
709         *cookiesString = stringCookiesList;
710 }
711
712 PassRefPtr<InspectorArray> InspectorAgent::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
713 {
714     RefPtr<InspectorArray> cookies = InspectorArray::create();
715
716     ListHashSet<Cookie>::iterator end = cookiesList.end();
717     ListHashSet<Cookie>::iterator it = cookiesList.begin();
718     for (int i = 0; it != end; ++it, i++)
719         cookies->pushObject(buildObjectForCookie(*it));
720
721     return cookies;
722 }
723
724 PassRefPtr<InspectorObject> InspectorAgent::buildObjectForCookie(const Cookie& cookie)
725 {
726     RefPtr<InspectorObject> value = InspectorObject::create();
727     value->setString("name", cookie.name);
728     value->setString("value", cookie.value);
729     value->setString("domain", cookie.domain);
730     value->setString("path", cookie.path);
731     value->setNumber("expires", cookie.expires);
732     value->setNumber("size", (cookie.name.length() + cookie.value.length()));
733     value->setBoolean("httpOnly", cookie.httpOnly);
734     value->setBoolean("secure", cookie.secure);
735     value->setBoolean("session", cookie.session);
736     return value;
737 }
738
739 void InspectorAgent::deleteCookie(ErrorString*, const String& cookieName, const String& domain)
740 {
741     for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) {
742         Document* document = frame->document();
743         if (document->url().host() != domain)
744             continue;
745         const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
746         CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
747         for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it)
748             WebCore::deleteCookie(document, KURL(ParsedURLString, it->second->url()), cookieName);
749     }
750 }
751
752 #if ENABLE(WEB_SOCKETS)
753 void InspectorAgent::didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL)
754 {
755     if (!enabled())
756         return;
757     ASSERT(m_inspectedPage);
758
759     if (m_resourceAgent)
760         m_resourceAgent->didCreateWebSocket(identifier, requestURL);
761     UNUSED_PARAM(documentURL);
762 }
763
764 void InspectorAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request)
765 {
766     if (m_resourceAgent)
767         m_resourceAgent->willSendWebSocketHandshakeRequest(identifier, request);
768 }
769
770 void InspectorAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response)
771 {
772     if (m_resourceAgent)
773         m_resourceAgent->didReceiveWebSocketHandshakeResponse(identifier, response);
774 }
775
776 void InspectorAgent::didCloseWebSocket(unsigned long identifier)
777 {
778     if (m_resourceAgent)
779         m_resourceAgent->didCloseWebSocket(identifier);
780 }
781 #endif // ENABLE(WEB_SOCKETS)
782
783 #if ENABLE(JAVASCRIPT_DEBUGGER)
784 bool InspectorAgent::isRecordingUserInitiatedProfile() const
785 {
786     return m_profilerAgent->isRecordingUserInitiatedProfile();
787 }
788
789 void InspectorAgent::startUserInitiatedProfiling()
790 {
791     if (!enabled())
792         return;
793     m_profilerAgent->startUserInitiatedProfiling();
794     m_state->setBoolean(InspectorAgentState::userInitiatedProfiling, true);
795 }
796
797 void InspectorAgent::stopUserInitiatedProfiling()
798 {
799     m_profilerAgent->stopUserInitiatedProfiling();
800     m_state->setBoolean(InspectorAgentState::userInitiatedProfiling, false);
801     showPanel(profilesPanelName);
802 }
803
804 bool InspectorAgent::profilerEnabled() const
805 {
806     return enabled() && m_profilerAgent->enabled();
807 }
808
809 void InspectorAgent::enableProfiler(ErrorString*)
810 {
811     if (profilerEnabled())
812         return;
813     m_state->setBoolean(InspectorAgentState::profilerEnabled, true);
814     m_profilerAgent->enable(false);
815 }
816
817 void InspectorAgent::disableProfiler(ErrorString*)
818 {
819     m_state->setBoolean(InspectorAgentState::profilerEnabled, false);
820     m_profilerAgent->disable();
821 }
822 #endif
823
824 #if ENABLE(JAVASCRIPT_DEBUGGER)
825 void InspectorAgent::startUserInitiatedDebugging()
826 {
827     if (debuggerEnabled())
828         return;
829
830     showPanel(scriptsPanelName);
831     if (!m_frontend) {
832         // We are called after show(), set the debuggerEnabled flag so that it was enabled
833         // upon frontend opening.
834         m_state->setBoolean(InspectorAgentState::debuggerEnabled, true);
835     } else
836         enableDebugger(true);
837 }
838
839 void InspectorAgent::enableDebugger(bool eraseStickyBreakpoints)
840 {
841     if (debuggerEnabled())
842         return;
843     m_state->setBoolean(InspectorAgentState::debuggerEnabled, true);
844     ASSERT(m_inspectedPage);
845
846     m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend, eraseStickyBreakpoints);
847     m_browserDebuggerAgent = InspectorBrowserDebuggerAgent::create(this, eraseStickyBreakpoints);
848
849     m_frontend->debuggerWasEnabled();
850 }
851
852 void InspectorAgent::disableDebugger(ErrorString*)
853 {
854     if (!enabled())
855         return;
856     ASSERT(m_inspectedPage);
857     m_debuggerAgent.clear();
858     m_browserDebuggerAgent.clear();
859
860     if (m_frontend) {
861         m_frontend->debuggerWasDisabled();
862         m_state->setBoolean(InspectorAgentState::debuggerEnabled, false);
863     }
864 }
865 #endif
866
867 void InspectorAgent::evaluateForTestInFrontend(long callId, const String& script)
868 {
869     if (m_frontend)
870         m_frontend->evaluateForTestInFrontend(callId, script);
871     else
872         m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
873 }
874
875 void InspectorAgent::didEvaluateForTestInFrontend(ErrorString*, long callId, const String& jsonResult)
876 {
877     ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
878     ScriptObject window;
879     ScriptGlobalObject::get(scriptState, "window", window);
880     ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
881     function.appendArgument(callId);
882     function.appendArgument(jsonResult);
883     function.call();
884 }
885
886 static Path quadToPath(const FloatQuad& quad)
887 {
888     Path quadPath;
889     quadPath.moveTo(quad.p1());
890     quadPath.addLineTo(quad.p2());
891     quadPath.addLineTo(quad.p3());
892     quadPath.addLineTo(quad.p4());
893     quadPath.closeSubpath();
894     return quadPath;
895 }
896
897 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
898 {
899     static const int outlineThickness = 2;
900     static const Color outlineColor(62, 86, 180, 228);
901
902     Path quadPath = quadToPath(quad);
903
904     // Clip out the quad, then draw with a 2px stroke to get a pixel
905     // of outline (because inflating a quad is hard)
906     {
907         context.save();
908         context.clipOut(quadPath);
909
910         context.setStrokeThickness(outlineThickness);
911         context.setStrokeColor(outlineColor, ColorSpaceDeviceRGB);
912         context.strokePath(quadPath);
913
914         context.restore();
915     }
916
917     // Now do the fill
918     context.setFillColor(fillColor, ColorSpaceDeviceRGB);
919     context.fillPath(quadPath);
920 }
921
922 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
923 {
924     context.save();
925     Path clipQuadPath = quadToPath(clipQuad);
926     context.clipOut(clipQuadPath);
927     drawOutlinedQuad(context, quad, fillColor);
928     context.restore();
929 }
930
931 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
932 {
933     static const Color contentBoxColor(125, 173, 217, 128);
934     static const Color paddingBoxColor(125, 173, 217, 160);
935     static const Color borderBoxColor(125, 173, 217, 192);
936     static const Color marginBoxColor(125, 173, 217, 228);
937
938     if (marginQuad != borderQuad)
939         drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
940     if (borderQuad != paddingQuad)
941         drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
942     if (paddingQuad != contentQuad)
943         drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
944
945     drawOutlinedQuad(context, contentQuad, contentBoxColor);
946 }
947
948 static void drawHighlightForLineBoxesOrSVGRenderer(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
949 {
950     static const Color lineBoxColor(125, 173, 217, 128);
951
952     for (size_t i = 0; i < lineBoxQuads.size(); ++i)
953         drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
954 }
955
956 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
957 {
958     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
959 }
960
961 static inline IntSize frameToMainFrameOffset(Frame* frame)
962 {
963     IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
964     return mainFramePoint - IntPoint();
965 }
966
967 void InspectorAgent::drawNodeHighlight(GraphicsContext& context) const
968 {
969     if (!m_highlightedNode)
970         return;
971
972     RenderObject* renderer = m_highlightedNode->renderer();
973     Frame* containingFrame = m_highlightedNode->document()->frame();
974     if (!renderer || !containingFrame)
975         return;
976
977     IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
978     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
979     boundingBox.move(mainFrameOffset);
980
981     IntRect titleReferenceBox = boundingBox;
982
983     ASSERT(m_inspectedPage);
984
985     FrameView* view = m_inspectedPage->mainFrame()->view();
986     FloatRect overlayRect = view->visibleContentRect();
987     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
988         overlayRect = view->visibleContentRect();
989     context.translate(-overlayRect.x(), -overlayRect.y());
990
991     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
992 #if ENABLE(SVG)
993     bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
994 #else
995     bool isSVGRenderer = false;
996 #endif
997
998     if (renderer->isBox() && !isSVGRenderer) {
999         RenderBox* renderBox = toRenderBox(renderer);
1000
1001         IntRect contentBox = renderBox->contentBoxRect();
1002
1003         IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
1004                            contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
1005         IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
1006                           paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
1007         IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
1008                           borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
1009
1010
1011         FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
1012         FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
1013         FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
1014         FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
1015
1016         absContentQuad.move(mainFrameOffset);
1017         absPaddingQuad.move(mainFrameOffset);
1018         absBorderQuad.move(mainFrameOffset);
1019         absMarginQuad.move(mainFrameOffset);
1020
1021         titleReferenceBox = absMarginQuad.enclosingBoundingBox();
1022
1023         drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
1024     } else if (renderer->isRenderInline() || isSVGRenderer) {
1025         // FIXME: We should show margins/padding/border for inlines.
1026         Vector<FloatQuad> lineBoxQuads;
1027         renderer->absoluteQuads(lineBoxQuads);
1028         for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
1029             lineBoxQuads[i] += mainFrameOffset;
1030
1031         drawHighlightForLineBoxesOrSVGRenderer(context, lineBoxQuads);
1032     }
1033
1034     // Draw node title if necessary.
1035
1036     if (!m_highlightedNode->isElementNode())
1037         return;
1038
1039     WebCore::Settings* settings = containingFrame->settings();
1040     drawElementTitle(context, titleReferenceBox, overlayRect, settings);
1041 }
1042
1043 void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings* settings) const
1044 {
1045     static const int rectInflatePx = 4;
1046     static const int fontHeightPx = 12;
1047     static const int borderWidthPx = 1;
1048     static const Color tooltipBackgroundColor(255, 255, 194, 255);
1049     static const Color tooltipBorderColor(Color::black);
1050     static const Color tooltipFontColor(Color::black);
1051
1052     Element* element = static_cast<Element*>(m_highlightedNode.get());
1053     bool isXHTML = element->document()->isXHTMLDocument();
1054     String nodeTitle = isXHTML ? element->nodeName() : element->nodeName().lower();
1055     const AtomicString& idValue = element->getIdAttribute();
1056     if (!idValue.isNull() && !idValue.isEmpty()) {
1057         nodeTitle += "#";
1058         nodeTitle += idValue;
1059     }
1060     if (element->hasClass() && element->isStyledElement()) {
1061         const SpaceSplitString& classNamesString = static_cast<StyledElement*>(element)->classNames();
1062         size_t classNameCount = classNamesString.size();
1063         if (classNameCount) {
1064             HashSet<AtomicString> usedClassNames;
1065             for (size_t i = 0; i < classNameCount; ++i) {
1066                 const AtomicString& className = classNamesString[i];
1067                 if (usedClassNames.contains(className))
1068                     continue;
1069                 usedClassNames.add(className);
1070                 nodeTitle += ".";
1071                 nodeTitle += className;
1072             }
1073         }
1074     }
1075
1076     Element* highlightedElement = m_highlightedNode->isElementNode() ? static_cast<Element*>(m_highlightedNode.get()) : 0;
1077     nodeTitle += " [";
1078     nodeTitle += String::number(highlightedElement ? highlightedElement->offsetWidth() : boundingBox.width());
1079     nodeTitle.append(static_cast<UChar>(0x00D7)); // &times;
1080     nodeTitle += String::number(highlightedElement ? highlightedElement->offsetHeight() : boundingBox.height());
1081     nodeTitle += "]";
1082
1083     FontDescription desc;
1084     FontFamily family;
1085     family.setFamily(settings->fixedFontFamily());
1086     desc.setFamily(family);
1087     desc.setComputedSize(fontHeightPx);
1088     Font font = Font(desc, 0, 0);
1089     font.update(0);
1090
1091     TextRun nodeTitleRun(nodeTitle);
1092     IntPoint titleBasePoint = IntPoint(boundingBox.x(), boundingBox.maxY() - 1);
1093     titleBasePoint.move(rectInflatePx, rectInflatePx);
1094     IntRect titleRect = enclosingIntRect(font.selectionRectForText(nodeTitleRun, titleBasePoint, fontHeightPx));
1095     titleRect.inflate(rectInflatePx);
1096
1097     // The initial offsets needed to compensate for a 1px-thick border stroke (which is not a part of the rectangle).
1098     int dx = -borderWidthPx;
1099     int dy = borderWidthPx;
1100
1101     // If the tip sticks beyond the right of overlayRect, right-align the tip with the said boundary.
1102     if (titleRect.maxX() > overlayRect.maxX())
1103         dx = overlayRect.maxX() - titleRect.maxX();
1104
1105     // If the tip sticks beyond the left of overlayRect, left-align the tip with the said boundary.
1106     if (titleRect.x() + dx < overlayRect.x())
1107         dx = overlayRect.x() - titleRect.x() - borderWidthPx;
1108
1109     // If the tip sticks beyond the bottom of overlayRect, show the tip at top of bounding box.
1110     if (titleRect.maxY() > overlayRect.maxY()) {
1111         dy = boundingBox.y() - titleRect.maxY() - borderWidthPx;
1112         // If the tip still sticks beyond the bottom of overlayRect, bottom-align the tip with the said boundary.
1113         if (titleRect.maxY() + dy > overlayRect.maxY())
1114             dy = overlayRect.maxY() - titleRect.maxY();
1115     }
1116
1117     // If the tip sticks beyond the top of overlayRect, show the tip at top of overlayRect.
1118     if (titleRect.y() + dy < overlayRect.y())
1119         dy = overlayRect.y() - titleRect.y() + borderWidthPx;
1120
1121     titleRect.move(dx, dy);
1122     context.setStrokeColor(tooltipBorderColor, ColorSpaceDeviceRGB);
1123     context.setStrokeThickness(borderWidthPx);
1124     context.setFillColor(tooltipBackgroundColor, ColorSpaceDeviceRGB);
1125     context.drawRect(titleRect);
1126     context.setFillColor(tooltipFontColor, ColorSpaceDeviceRGB);
1127     context.drawText(font, nodeTitleRun, IntPoint(titleRect.x() + rectInflatePx, titleRect.y() + font.fontMetrics().height()));
1128 }
1129
1130 void InspectorAgent::openInInspectedWindow(ErrorString*, const String& url)
1131 {
1132     Frame* mainFrame = m_inspectedPage->mainFrame();
1133
1134     FrameLoadRequest request(mainFrame->document()->securityOrigin(), ResourceRequest(), "_blank");
1135
1136     bool created;
1137     WindowFeatures windowFeatures;
1138     Frame* newFrame = WebCore::createWindow(mainFrame, mainFrame, request, windowFeatures, created);
1139     if (!newFrame)
1140         return;
1141
1142     UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
1143     newFrame->loader()->setOpener(mainFrame);
1144     newFrame->page()->setOpenedByDOM();
1145     newFrame->loader()->changeLocation(mainFrame->document()->securityOrigin(), newFrame->loader()->completeURL(url), "", false, false);
1146 }
1147
1148 void InspectorAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source)
1149 {
1150     m_scriptsToEvaluateOnLoad.append(source);
1151 }
1152
1153 void InspectorAgent::removeAllScriptsToEvaluateOnLoad(ErrorString*)
1154 {
1155     m_scriptsToEvaluateOnLoad.clear();
1156 }
1157
1158 void InspectorAgent::setInspectorExtensionAPI(const String& source)
1159 {
1160     m_inspectorExtensionAPI = source;
1161 }
1162
1163 KURL InspectorAgent::inspectedURL() const
1164 {
1165     return m_inspectedPage->mainFrame()->document()->url();
1166 }
1167
1168 KURL InspectorAgent::inspectedURLWithoutFragment() const
1169 {
1170     KURL url = inspectedURL();
1171     url.removeFragmentIdentifier();
1172     return url;
1173 }
1174
1175 void InspectorAgent::reloadPage(ErrorString*, bool ignoreCache)
1176 {
1177     m_inspectedPage->mainFrame()->loader()->reload(ignoreCache);
1178 }
1179
1180 bool InspectorAgent::enabled() const
1181 {
1182     if (!m_inspectedPage)
1183         return false;
1184     return m_inspectedPage->settings()->developerExtrasEnabled();
1185 }
1186
1187 void InspectorAgent::showConsole()
1188 {
1189     showPanel(consolePanelName);
1190 }
1191
1192 void InspectorAgent::showPanel(const String& panel)
1193 {
1194     if (!m_frontend) {
1195         m_showPanelAfterVisible = panel;
1196         return;
1197     }
1198     m_frontend->showPanel(panel);
1199 }
1200
1201 } // namespace WebCore
1202
1203 #endif // ENABLE(INSPECTOR)