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