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