2 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "InspectorAgent.h"
35 #include "CachedResource.h"
36 #include "CachedResourceLoader.h"
39 #include "CookieJar.h"
40 #include "DOMWindow.h"
41 #include "DOMWrapperWorld.h"
43 #include "DocumentLoader.h"
45 #include "FloatConversion.h"
46 #include "FloatQuad.h"
47 #include "FloatRect.h"
49 #include "FrameLoadRequest.h"
50 #include "FrameLoader.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "GraphicsContext.h"
54 #include "HTMLFrameOwnerElement.h"
55 #include "HTTPHeaderMap.h"
56 #include "HitTestResult.h"
57 #include "InjectedScript.h"
58 #include "InjectedScriptHost.h"
59 #include "InspectorBrowserDebuggerAgent.h"
60 #include "InspectorCSSAgent.h"
61 #include "InspectorClient.h"
62 #include "InspectorConsoleAgent.h"
63 #include "InspectorController.h"
64 #include "InspectorDOMAgent.h"
65 #include "InspectorDebuggerAgent.h"
66 #include "InspectorFrontend.h"
67 #include "InspectorFrontendClient.h"
68 #include "InspectorInstrumentation.h"
69 #include "InspectorProfilerAgent.h"
70 #include "InspectorResourceAgent.h"
71 #include "InspectorRuntimeAgent.h"
72 #include "InspectorState.h"
73 #include "InspectorTimelineAgent.h"
74 #include "InspectorValues.h"
75 #include "InspectorWorkerResource.h"
76 #include "InstrumentingAgents.h"
79 #include "ProgressTracker.h"
81 #include "RenderInline.h"
82 #include "ResourceRequest.h"
83 #include "ResourceResponse.h"
84 #include "ScriptArguments.h"
85 #include "ScriptCallStack.h"
86 #include "ScriptFunctionCall.h"
87 #include "ScriptObject.h"
88 #include "ScriptProfile.h"
89 #include "ScriptProfiler.h"
90 #include "ScriptSourceCode.h"
91 #include "ScriptState.h"
92 #include "SecurityOrigin.h"
94 #include "SharedBuffer.h"
95 #include "TextEncoding.h"
96 #include "TextIterator.h"
98 #include "UserGestureIndicator.h"
99 #include "WindowFeatures.h"
100 #include <wtf/CurrentTime.h>
101 #include <wtf/ListHashSet.h>
102 #include <wtf/RefCounted.h>
103 #include <wtf/StdLibExtras.h>
104 #include <wtf/UnusedParam.h>
105 #include <wtf/text/StringConcatenate.h>
108 #include "InspectorDatabaseAgent.h"
111 #if ENABLE(DOM_STORAGE)
112 #include "InspectorDOMStorageAgent.h"
115 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
116 #include "InspectorApplicationCacheAgent.h"
123 namespace InspectorAgentState {
124 static const char searchingForNode[] = "searchingForNode";
125 static const char timelineProfilerEnabled[] = "timelineProfilerEnabled";
126 static const char userInitiatedProfiling[] = "userInitiatedProfiling";
127 static const char debuggerEnabled[] = "debuggerEnabled";
128 static const char profilerEnabled[] = "profilerEnabled";
131 static const char scriptsPanelName[] = "scripts";
132 static const char consolePanelName[] = "console";
133 static const char profilesPanelName[] = "profiles";
135 InspectorAgent::InspectorAgent(Page* page, InspectorClient* client)
136 : m_inspectedPage(page)
139 , m_instrumentingAgents(new InstrumentingAgents())
140 , m_injectedScriptHost(InjectedScriptHost::create(this))
141 , m_domAgent(InspectorDOMAgent::create(m_instrumentingAgents.get(), m_injectedScriptHost.get()))
142 , m_cssAgent(new InspectorCSSAgent(m_domAgent.get()))
144 , m_databaseAgent(InspectorDatabaseAgent::create(m_instrumentingAgents.get()))
146 #if ENABLE(DOM_STORAGE)
147 , m_domStorageAgent(InspectorDOMStorageAgent::create(m_instrumentingAgents.get()))
149 , m_state(new InspectorState(client))
150 , m_timelineAgent(InspectorTimelineAgent::create(m_instrumentingAgents.get(), m_state.get()))
151 , m_consoleAgent(new InspectorConsoleAgent(m_instrumentingAgents.get(), this, m_state.get(), m_injectedScriptHost.get(), m_domAgent.get()))
152 #if ENABLE(JAVASCRIPT_DEBUGGER)
153 , m_profilerAgent(InspectorProfilerAgent::create(this))
156 ASSERT_ARG(page, page);
157 ASSERT_ARG(client, client);
158 InspectorInstrumentation::bindInspectorAgent(m_inspectedPage, this);
161 InspectorAgent::~InspectorAgent()
163 // These should have been cleared in inspectedPageDestroyed().
165 ASSERT(!m_inspectedPage);
166 ASSERT(!m_highlightedNode);
169 void InspectorAgent::inspectedPageDestroyed()
172 m_frontend->disconnectFromBackend();
175 hideHighlight(&error);
177 #if ENABLE(JAVASCRIPT_DEBUGGER)
178 m_debuggerAgent.clear();
179 m_browserDebuggerAgent.clear();
182 ASSERT(m_inspectedPage);
183 InspectorInstrumentation::unbindInspectorAgent(m_inspectedPage);
186 releaseFrontendLifetimeAgents();
187 m_injectedScriptHost->disconnectController();
189 m_client->inspectorDestroyed();
193 bool InspectorAgent::searchingForNodeInPage() const
195 return m_state->getBoolean(InspectorAgentState::searchingForNode);
198 void InspectorAgent::restoreInspectorStateFromCookie(const String& inspectorStateCookie)
200 m_state->loadFromCookie(inspectorStateCookie);
202 m_frontend->frontendReused();
203 m_frontend->inspectedURLChanged(inspectedURL().string());
204 pushDataCollectedOffline();
206 m_resourceAgent = InspectorResourceAgent::restore(m_inspectedPage, m_state.get(), m_frontend);
207 m_timelineAgent->restore(m_state.get(), m_frontend);
209 #if ENABLE(JAVASCRIPT_DEBUGGER)
210 restoreDebugger(false);
211 restoreProfiler(ProfilerRestoreResetAgent);
212 if (m_state->getBoolean(InspectorAgentState::userInitiatedProfiling))
213 startUserInitiatedProfiling();
217 void InspectorAgent::inspect(Node* node)
219 if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
220 node = node->parentNode();
221 m_nodeToFocus = node;
229 void InspectorAgent::focusNode()
235 ASSERT(m_nodeToFocus);
237 m_domAgent->inspect(m_nodeToFocus.get());
241 void InspectorAgent::highlight(ErrorString*, Node* node)
245 ASSERT_ARG(node, node);
246 m_highlightedNode = node;
247 m_client->highlight(node);
250 void InspectorAgent::highlightDOMNode(ErrorString* error, long nodeId)
253 if (m_domAgent && (node = m_domAgent->nodeForId(nodeId)))
254 highlight(error, node);
257 void InspectorAgent::highlightFrame(ErrorString* error, unsigned long frameId)
259 Frame* mainFrame = m_inspectedPage->mainFrame();
260 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext(mainFrame)) {
261 if (reinterpret_cast<uintptr_t>(frame) == frameId && frame->ownerElement()) {
262 highlight(error, frame->ownerElement());
268 void InspectorAgent::hideHighlight(ErrorString*)
272 m_highlightedNode = 0;
273 m_client->hideHighlight();
276 void InspectorAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
278 if (!enabled() || !searchingForNodeInPage())
281 Node* node = result.innerNode();
282 while (node && node->nodeType() == Node::TEXT_NODE)
283 node = node->parentNode();
286 highlight(&error, node);
290 bool InspectorAgent::handleMousePress()
292 if (!enabled() || !searchingForNodeInPage())
295 if (m_highlightedNode) {
296 RefPtr<Node> node = m_highlightedNode;
297 setSearchingForNode(false);
303 void InspectorAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
305 if (world != mainThreadNormalWorld())
309 if (m_frontend && frame == m_inspectedPage->mainFrame())
310 m_injectedScriptHost->discardInjectedScripts();
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);
321 if (!m_inspectorExtensionAPI.isEmpty())
322 m_injectedScriptHost->injectScript(m_inspectorExtensionAPI, mainWorldScriptState(frame));
325 void InspectorAgent::setSearchingForNode(bool enabled)
327 if (searchingForNodeInPage() == enabled)
329 m_state->setBoolean(InspectorAgentState::searchingForNode, enabled);
332 hideHighlight(&error);
336 void InspectorAgent::setSearchingForNode(ErrorString*, bool enabled, bool* newState)
339 setSearchingForNode(enabled);
342 void InspectorAgent::setFrontend(InspectorFrontend* inspectorFrontend)
344 // We can reconnect to existing front-end -> unmute state.
347 m_frontend = inspectorFrontend;
348 createFrontendLifetimeAgents();
350 m_domAgent->setFrontend(m_frontend);
351 m_consoleAgent->setFrontend(m_frontend);
352 m_timelineAgent->setFrontend(m_frontend);
354 m_databaseAgent->setFrontend(m_frontend);
356 #if ENABLE(DOM_STORAGE)
357 m_domStorageAgent->setFrontend(m_frontend);
359 // Initialize Web Inspector title.
360 m_frontend->inspectedURLChanged(inspectedURL().string());
363 void InspectorAgent::disconnectFrontend()
368 // Destroying agents would change the state, but we don't want that.
369 // Pre-disconnect state will be used to restore inspector agents.
375 #if ENABLE(JAVASCRIPT_DEBUGGER)
376 // If the window is being closed with the debugger enabled,
377 // remember this state to re-enable debugger on the next window
379 disableDebugger(&error);
381 setSearchingForNode(false);
383 hideHighlight(&error);
385 #if ENABLE(JAVASCRIPT_DEBUGGER)
386 m_profilerAgent->setFrontend(0);
387 m_profilerAgent->stopUserInitiatedProfiling(true);
390 m_consoleAgent->clearFrontend();
391 m_domAgent->clearFrontend();
392 m_timelineAgent->clearFrontend();
394 m_databaseAgent->clearFrontend();
396 #if ENABLE(DOM_STORAGE)
397 m_domStorageAgent->clearFrontend();
400 releaseFrontendLifetimeAgents();
401 m_userAgentOverride = "";
404 InspectorResourceAgent* InspectorAgent::resourceAgent()
406 if (!m_resourceAgent && m_frontend)
407 m_resourceAgent = InspectorResourceAgent::create(m_inspectedPage, m_state.get(), m_frontend);
408 return m_resourceAgent.get();
411 void InspectorAgent::createFrontendLifetimeAgents()
413 m_runtimeAgent = InspectorRuntimeAgent::create(m_injectedScriptHost.get());
415 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
416 m_applicationCacheAgent = new InspectorApplicationCacheAgent(m_inspectedPage->mainFrame()->loader()->documentLoader(), m_frontend);
420 void InspectorAgent::releaseFrontendLifetimeAgents()
422 m_resourceAgent.clear();
423 m_runtimeAgent.clear();
424 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
425 m_applicationCacheAgent.clear();
429 void InspectorAgent::populateScriptObjects(ErrorString*)
435 #if ENABLE(JAVASCRIPT_DEBUGGER)
436 if (m_profilerAgent->enabled())
437 m_frontend->profilerWasEnabled();
440 pushDataCollectedOffline();
445 if (!m_showPanelAfterVisible.isEmpty()) {
446 m_frontend->showPanel(m_showPanelAfterVisible);
447 m_showPanelAfterVisible = "";
450 restoreDebugger(true);
451 restoreProfiler(ProfilerRestoreNoAction);
453 // Dispatch pending frontend commands
454 for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
455 m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
456 m_pendingEvaluateTestCommands.clear();
459 void InspectorAgent::pushDataCollectedOffline()
461 m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
463 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS)
464 WorkersMap::iterator workersEnd = m_workers.end();
465 for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it) {
466 InspectorWorkerResource* worker = it->second.get();
467 m_frontend->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker());
472 void InspectorAgent::restoreDebugger(bool eraseStickyBreakpoints)
475 #if ENABLE(JAVASCRIPT_DEBUGGER)
476 if (m_state->getBoolean(InspectorAgentState::debuggerEnabled))
477 enableDebugger(eraseStickyBreakpoints);
481 void InspectorAgent::restoreProfiler(ProfilerRestoreAction action)
484 #if ENABLE(JAVASCRIPT_DEBUGGER)
485 m_profilerAgent->setFrontend(m_frontend);
486 if (m_state->getBoolean(InspectorAgentState::profilerEnabled)) {
488 enableProfiler(&error);
490 if (action == ProfilerRestoreResetAgent)
491 m_profilerAgent->resetFrontendProfiles();
495 void InspectorAgent::didCommitLoad(DocumentLoader* loader)
501 m_resourceAgent->didCommitLoad(loader);
503 ASSERT(m_inspectedPage);
505 if (loader->frame() == m_inspectedPage->mainFrame()) {
507 m_frontend->inspectedURLChanged(loader->url().string());
509 m_injectedScriptHost->discardInjectedScripts();
510 m_consoleAgent->reset();
512 if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
513 timelineAgent->didCommitLoad();
515 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
516 if (m_applicationCacheAgent)
517 m_applicationCacheAgent->didCommitLoad(loader);
520 #if ENABLE(JAVASCRIPT_DEBUGGER)
521 if (m_debuggerAgent) {
522 KURL url = inspectedURLWithoutFragment();
523 m_debuggerAgent->inspectedURLChanged(url);
524 if (m_browserDebuggerAgent)
525 m_browserDebuggerAgent->inspectedURLChanged(url);
529 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
530 m_profilerAgent->stopUserInitiatedProfiling(true);
531 m_profilerAgent->resetState();
543 m_databaseAgent->clearResources();
545 #if ENABLE(DOM_STORAGE)
546 m_domStorageAgent->clearResources();
548 if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent())
549 domAgent->setDocument(m_inspectedPage->mainFrame()->document());
553 void InspectorAgent::domContentLoadedEventFired(DocumentLoader* loader, const KURL& url)
555 if (!enabled() || !isMainResourceLoader(loader, url))
558 if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent())
559 domAgent->mainFrameDOMContentLoaded();
560 if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
561 timelineAgent->didMarkDOMContentEvent();
563 m_frontend->domContentEventFired(currentTime());
566 void InspectorAgent::loadEventFired(DocumentLoader* loader, const KURL& url)
571 if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent())
572 domAgent->loadEventFired(loader->frame()->document());
574 if (!isMainResourceLoader(loader, url))
577 if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
578 timelineAgent->didMarkLoadEvent();
580 m_frontend->loadEventFired(currentTime());
583 bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
585 return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
588 void InspectorAgent::setUserAgentOverride(ErrorString*, const String& userAgent)
590 m_userAgentOverride = userAgent;
593 void InspectorAgent::applyUserAgentOverride(String* userAgent) const
595 if (!m_userAgentOverride.isEmpty())
596 *userAgent = m_userAgentOverride;
600 class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task {
602 static PassOwnPtr<PostWorkerNotificationToFrontendTask> create(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
604 return new PostWorkerNotificationToFrontendTask(worker, action);
608 PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
614 virtual void performTask(ScriptExecutionContext* scriptContext)
616 if (scriptContext->isDocument()) {
617 if (InspectorAgent* inspectorAgent = static_cast<Document*>(scriptContext)->page()->inspectorController()->m_inspectorAgent.get())
618 inspectorAgent->postWorkerNotificationToFrontend(*m_worker, m_action);
623 RefPtr<InspectorWorkerResource> m_worker;
624 InspectorAgent::WorkerAction m_action;
627 void InspectorAgent::postWorkerNotificationToFrontend(const InspectorWorkerResource& worker, InspectorAgent::WorkerAction action)
631 #if ENABLE(JAVASCRIPT_DEBUGGER)
633 case InspectorAgent::WorkerCreated:
634 m_frontend->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker());
636 case InspectorAgent::WorkerDestroyed:
637 m_frontend->didDestroyWorker(worker.id());
643 void InspectorAgent::didCreateWorker(intptr_t id, const String& url, bool isSharedWorker)
648 RefPtr<InspectorWorkerResource> workerResource(InspectorWorkerResource::create(id, url, isSharedWorker));
649 m_workers.set(id, workerResource);
650 if (m_inspectedPage && m_frontend)
651 m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource, InspectorAgent::WorkerCreated));
654 void InspectorAgent::didDestroyWorker(intptr_t id)
659 WorkersMap::iterator workerResource = m_workers.find(id);
660 if (workerResource == m_workers.end())
662 if (m_inspectedPage && m_frontend)
663 m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource->second, InspectorAgent::WorkerDestroyed));
664 m_workers.remove(workerResource);
666 #endif // ENABLE(WORKERS)
668 void InspectorAgent::getCookies(ErrorString*, RefPtr<InspectorArray>* cookies, WTF::String* cookiesString)
670 // If we can get raw cookies.
671 ListHashSet<Cookie> rawCookiesList;
673 // If we can't get raw cookies - fall back to String representation
674 String stringCookiesList;
676 // Return value to getRawCookies should be the same for every call because
677 // the return value is platform/network backend specific, and the call will
678 // always return the same true/false value.
679 bool rawCookiesImplemented = false;
681 for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) {
682 Document* document = frame->document();
683 const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
684 CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
685 for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
686 Vector<Cookie> docCookiesList;
687 rawCookiesImplemented = getRawCookies(document, KURL(ParsedURLString, it->second->url()), docCookiesList);
689 if (!rawCookiesImplemented) {
690 // FIXME: We need duplication checking for the String representation of cookies.
691 ExceptionCode ec = 0;
692 stringCookiesList += document->cookie(ec);
693 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
694 // because "document" is the document of the main frame of the page.
697 int cookiesSize = docCookiesList.size();
698 for (int i = 0; i < cookiesSize; i++) {
699 if (!rawCookiesList.contains(docCookiesList[i]))
700 rawCookiesList.add(docCookiesList[i]);
706 if (rawCookiesImplemented)
707 *cookies = buildArrayForCookies(rawCookiesList);
709 *cookiesString = stringCookiesList;
712 PassRefPtr<InspectorArray> InspectorAgent::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
714 RefPtr<InspectorArray> cookies = InspectorArray::create();
716 ListHashSet<Cookie>::iterator end = cookiesList.end();
717 ListHashSet<Cookie>::iterator it = cookiesList.begin();
718 for (int i = 0; it != end; ++it, i++)
719 cookies->pushObject(buildObjectForCookie(*it));
724 PassRefPtr<InspectorObject> InspectorAgent::buildObjectForCookie(const Cookie& cookie)
726 RefPtr<InspectorObject> value = InspectorObject::create();
727 value->setString("name", cookie.name);
728 value->setString("value", cookie.value);
729 value->setString("domain", cookie.domain);
730 value->setString("path", cookie.path);
731 value->setNumber("expires", cookie.expires);
732 value->setNumber("size", (cookie.name.length() + cookie.value.length()));
733 value->setBoolean("httpOnly", cookie.httpOnly);
734 value->setBoolean("secure", cookie.secure);
735 value->setBoolean("session", cookie.session);
739 void InspectorAgent::deleteCookie(ErrorString*, const String& cookieName, const String& domain)
741 for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) {
742 Document* document = frame->document();
743 if (document->url().host() != domain)
745 const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
746 CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
747 for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it)
748 WebCore::deleteCookie(document, KURL(ParsedURLString, it->second->url()), cookieName);
752 #if ENABLE(WEB_SOCKETS)
753 void InspectorAgent::didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL)
757 ASSERT(m_inspectedPage);
760 m_resourceAgent->didCreateWebSocket(identifier, requestURL);
761 UNUSED_PARAM(documentURL);
764 void InspectorAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request)
767 m_resourceAgent->willSendWebSocketHandshakeRequest(identifier, request);
770 void InspectorAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response)
773 m_resourceAgent->didReceiveWebSocketHandshakeResponse(identifier, response);
776 void InspectorAgent::didCloseWebSocket(unsigned long identifier)
779 m_resourceAgent->didCloseWebSocket(identifier);
781 #endif // ENABLE(WEB_SOCKETS)
783 #if ENABLE(JAVASCRIPT_DEBUGGER)
784 bool InspectorAgent::isRecordingUserInitiatedProfile() const
786 return m_profilerAgent->isRecordingUserInitiatedProfile();
789 void InspectorAgent::startUserInitiatedProfiling()
793 m_profilerAgent->startUserInitiatedProfiling();
794 m_state->setBoolean(InspectorAgentState::userInitiatedProfiling, true);
797 void InspectorAgent::stopUserInitiatedProfiling()
799 m_profilerAgent->stopUserInitiatedProfiling();
800 m_state->setBoolean(InspectorAgentState::userInitiatedProfiling, false);
801 showPanel(profilesPanelName);
804 bool InspectorAgent::profilerEnabled() const
806 return enabled() && m_profilerAgent->enabled();
809 void InspectorAgent::enableProfiler(ErrorString*)
811 if (profilerEnabled())
813 m_state->setBoolean(InspectorAgentState::profilerEnabled, true);
814 m_profilerAgent->enable(false);
817 void InspectorAgent::disableProfiler(ErrorString*)
819 m_state->setBoolean(InspectorAgentState::profilerEnabled, false);
820 m_profilerAgent->disable();
824 #if ENABLE(JAVASCRIPT_DEBUGGER)
825 void InspectorAgent::startUserInitiatedDebugging()
827 if (debuggerEnabled())
830 showPanel(scriptsPanelName);
832 // We are called after show(), set the debuggerEnabled flag so that it was enabled
833 // upon frontend opening.
834 m_state->setBoolean(InspectorAgentState::debuggerEnabled, true);
836 enableDebugger(true);
839 void InspectorAgent::enableDebugger(bool eraseStickyBreakpoints)
841 if (debuggerEnabled())
843 m_state->setBoolean(InspectorAgentState::debuggerEnabled, true);
844 ASSERT(m_inspectedPage);
846 m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend, eraseStickyBreakpoints);
847 m_browserDebuggerAgent = InspectorBrowserDebuggerAgent::create(this, eraseStickyBreakpoints);
849 m_frontend->debuggerWasEnabled();
852 void InspectorAgent::disableDebugger(ErrorString*)
856 ASSERT(m_inspectedPage);
857 m_debuggerAgent.clear();
858 m_browserDebuggerAgent.clear();
861 m_frontend->debuggerWasDisabled();
862 m_state->setBoolean(InspectorAgentState::debuggerEnabled, false);
867 void InspectorAgent::evaluateForTestInFrontend(long callId, const String& script)
870 m_frontend->evaluateForTestInFrontend(callId, script);
872 m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
875 void InspectorAgent::didEvaluateForTestInFrontend(ErrorString*, long callId, const String& jsonResult)
877 ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
879 ScriptGlobalObject::get(scriptState, "window", window);
880 ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
881 function.appendArgument(callId);
882 function.appendArgument(jsonResult);
886 static Path quadToPath(const FloatQuad& quad)
889 quadPath.moveTo(quad.p1());
890 quadPath.addLineTo(quad.p2());
891 quadPath.addLineTo(quad.p3());
892 quadPath.addLineTo(quad.p4());
893 quadPath.closeSubpath();
897 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
899 static const int outlineThickness = 2;
900 static const Color outlineColor(62, 86, 180, 228);
902 Path quadPath = quadToPath(quad);
904 // Clip out the quad, then draw with a 2px stroke to get a pixel
905 // of outline (because inflating a quad is hard)
908 context.clipOut(quadPath);
910 context.setStrokeThickness(outlineThickness);
911 context.setStrokeColor(outlineColor, ColorSpaceDeviceRGB);
912 context.strokePath(quadPath);
918 context.setFillColor(fillColor, ColorSpaceDeviceRGB);
919 context.fillPath(quadPath);
922 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
925 Path clipQuadPath = quadToPath(clipQuad);
926 context.clipOut(clipQuadPath);
927 drawOutlinedQuad(context, quad, fillColor);
931 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
933 static const Color contentBoxColor(125, 173, 217, 128);
934 static const Color paddingBoxColor(125, 173, 217, 160);
935 static const Color borderBoxColor(125, 173, 217, 192);
936 static const Color marginBoxColor(125, 173, 217, 228);
938 if (marginQuad != borderQuad)
939 drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
940 if (borderQuad != paddingQuad)
941 drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
942 if (paddingQuad != contentQuad)
943 drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
945 drawOutlinedQuad(context, contentQuad, contentBoxColor);
948 static void drawHighlightForLineBoxesOrSVGRenderer(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
950 static const Color lineBoxColor(125, 173, 217, 128);
952 for (size_t i = 0; i < lineBoxQuads.size(); ++i)
953 drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
956 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
958 rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
961 static inline IntSize frameToMainFrameOffset(Frame* frame)
963 IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
964 return mainFramePoint - IntPoint();
967 void InspectorAgent::drawNodeHighlight(GraphicsContext& context) const
969 if (!m_highlightedNode)
972 RenderObject* renderer = m_highlightedNode->renderer();
973 Frame* containingFrame = m_highlightedNode->document()->frame();
974 if (!renderer || !containingFrame)
977 IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
978 IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
979 boundingBox.move(mainFrameOffset);
981 IntRect titleReferenceBox = boundingBox;
983 ASSERT(m_inspectedPage);
985 FrameView* view = m_inspectedPage->mainFrame()->view();
986 FloatRect overlayRect = view->visibleContentRect();
987 if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
988 overlayRect = view->visibleContentRect();
989 context.translate(-overlayRect.x(), -overlayRect.y());
991 // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
993 bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
995 bool isSVGRenderer = false;
998 if (renderer->isBox() && !isSVGRenderer) {
999 RenderBox* renderBox = toRenderBox(renderer);
1001 IntRect contentBox = renderBox->contentBoxRect();
1003 IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
1004 contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
1005 IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
1006 paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
1007 IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
1008 borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
1011 FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
1012 FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
1013 FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
1014 FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
1016 absContentQuad.move(mainFrameOffset);
1017 absPaddingQuad.move(mainFrameOffset);
1018 absBorderQuad.move(mainFrameOffset);
1019 absMarginQuad.move(mainFrameOffset);
1021 titleReferenceBox = absMarginQuad.enclosingBoundingBox();
1023 drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
1024 } else if (renderer->isRenderInline() || isSVGRenderer) {
1025 // FIXME: We should show margins/padding/border for inlines.
1026 Vector<FloatQuad> lineBoxQuads;
1027 renderer->absoluteQuads(lineBoxQuads);
1028 for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
1029 lineBoxQuads[i] += mainFrameOffset;
1031 drawHighlightForLineBoxesOrSVGRenderer(context, lineBoxQuads);
1034 // Draw node title if necessary.
1036 if (!m_highlightedNode->isElementNode())
1039 WebCore::Settings* settings = containingFrame->settings();
1040 drawElementTitle(context, titleReferenceBox, overlayRect, settings);
1043 void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings* settings) const
1045 static const int rectInflatePx = 4;
1046 static const int fontHeightPx = 12;
1047 static const int borderWidthPx = 1;
1048 static const Color tooltipBackgroundColor(255, 255, 194, 255);
1049 static const Color tooltipBorderColor(Color::black);
1050 static const Color tooltipFontColor(Color::black);
1052 Element* element = static_cast<Element*>(m_highlightedNode.get());
1053 bool isXHTML = element->document()->isXHTMLDocument();
1054 String nodeTitle = isXHTML ? element->nodeName() : element->nodeName().lower();
1055 const AtomicString& idValue = element->getIdAttribute();
1056 if (!idValue.isNull() && !idValue.isEmpty()) {
1058 nodeTitle += idValue;
1060 if (element->hasClass() && element->isStyledElement()) {
1061 const SpaceSplitString& classNamesString = static_cast<StyledElement*>(element)->classNames();
1062 size_t classNameCount = classNamesString.size();
1063 if (classNameCount) {
1064 HashSet<AtomicString> usedClassNames;
1065 for (size_t i = 0; i < classNameCount; ++i) {
1066 const AtomicString& className = classNamesString[i];
1067 if (usedClassNames.contains(className))
1069 usedClassNames.add(className);
1071 nodeTitle += className;
1076 Element* highlightedElement = m_highlightedNode->isElementNode() ? static_cast<Element*>(m_highlightedNode.get()) : 0;
1078 nodeTitle += String::number(highlightedElement ? highlightedElement->offsetWidth() : boundingBox.width());
1079 nodeTitle.append(static_cast<UChar>(0x00D7)); // ×
1080 nodeTitle += String::number(highlightedElement ? highlightedElement->offsetHeight() : boundingBox.height());
1083 FontDescription desc;
1085 family.setFamily(settings->fixedFontFamily());
1086 desc.setFamily(family);
1087 desc.setComputedSize(fontHeightPx);
1088 Font font = Font(desc, 0, 0);
1091 TextRun nodeTitleRun(nodeTitle);
1092 IntPoint titleBasePoint = IntPoint(boundingBox.x(), boundingBox.maxY() - 1);
1093 titleBasePoint.move(rectInflatePx, rectInflatePx);
1094 IntRect titleRect = enclosingIntRect(font.selectionRectForText(nodeTitleRun, titleBasePoint, fontHeightPx));
1095 titleRect.inflate(rectInflatePx);
1097 // The initial offsets needed to compensate for a 1px-thick border stroke (which is not a part of the rectangle).
1098 int dx = -borderWidthPx;
1099 int dy = borderWidthPx;
1101 // If the tip sticks beyond the right of overlayRect, right-align the tip with the said boundary.
1102 if (titleRect.maxX() > overlayRect.maxX())
1103 dx = overlayRect.maxX() - titleRect.maxX();
1105 // If the tip sticks beyond the left of overlayRect, left-align the tip with the said boundary.
1106 if (titleRect.x() + dx < overlayRect.x())
1107 dx = overlayRect.x() - titleRect.x() - borderWidthPx;
1109 // If the tip sticks beyond the bottom of overlayRect, show the tip at top of bounding box.
1110 if (titleRect.maxY() > overlayRect.maxY()) {
1111 dy = boundingBox.y() - titleRect.maxY() - borderWidthPx;
1112 // If the tip still sticks beyond the bottom of overlayRect, bottom-align the tip with the said boundary.
1113 if (titleRect.maxY() + dy > overlayRect.maxY())
1114 dy = overlayRect.maxY() - titleRect.maxY();
1117 // If the tip sticks beyond the top of overlayRect, show the tip at top of overlayRect.
1118 if (titleRect.y() + dy < overlayRect.y())
1119 dy = overlayRect.y() - titleRect.y() + borderWidthPx;
1121 titleRect.move(dx, dy);
1122 context.setStrokeColor(tooltipBorderColor, ColorSpaceDeviceRGB);
1123 context.setStrokeThickness(borderWidthPx);
1124 context.setFillColor(tooltipBackgroundColor, ColorSpaceDeviceRGB);
1125 context.drawRect(titleRect);
1126 context.setFillColor(tooltipFontColor, ColorSpaceDeviceRGB);
1127 context.drawText(font, nodeTitleRun, IntPoint(titleRect.x() + rectInflatePx, titleRect.y() + font.fontMetrics().height()));
1130 void InspectorAgent::openInInspectedWindow(ErrorString*, const String& url)
1132 Frame* mainFrame = m_inspectedPage->mainFrame();
1134 FrameLoadRequest request(mainFrame->document()->securityOrigin(), ResourceRequest(), "_blank");
1137 WindowFeatures windowFeatures;
1138 Frame* newFrame = WebCore::createWindow(mainFrame, mainFrame, request, windowFeatures, created);
1142 UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
1143 newFrame->loader()->setOpener(mainFrame);
1144 newFrame->page()->setOpenedByDOM();
1145 newFrame->loader()->changeLocation(mainFrame->document()->securityOrigin(), newFrame->loader()->completeURL(url), "", false, false);
1148 void InspectorAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source)
1150 m_scriptsToEvaluateOnLoad.append(source);
1153 void InspectorAgent::removeAllScriptsToEvaluateOnLoad(ErrorString*)
1155 m_scriptsToEvaluateOnLoad.clear();
1158 void InspectorAgent::setInspectorExtensionAPI(const String& source)
1160 m_inspectorExtensionAPI = source;
1163 KURL InspectorAgent::inspectedURL() const
1165 return m_inspectedPage->mainFrame()->document()->url();
1168 KURL InspectorAgent::inspectedURLWithoutFragment() const
1170 KURL url = inspectedURL();
1171 url.removeFragmentIdentifier();
1175 void InspectorAgent::reloadPage(ErrorString*, bool ignoreCache)
1177 m_inspectedPage->mainFrame()->loader()->reload(ignoreCache);
1180 bool InspectorAgent::enabled() const
1182 if (!m_inspectedPage)
1184 return m_inspectedPage->settings()->developerExtrasEnabled();
1187 void InspectorAgent::showConsole()
1189 showPanel(consolePanelName);
1192 void InspectorAgent::showPanel(const String& panel)
1195 m_showPanelAfterVisible = panel;
1198 m_frontend->showPanel(panel);
1201 } // namespace WebCore
1203 #endif // ENABLE(INSPECTOR)