2 * Copyright (C) 2007, 2008, 2009 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 "InspectorController.h"
36 #include "CachedResource.h"
38 #include "ConsoleMessage.h"
40 #include "CookieJar.h"
42 #include "DocumentLoader.h"
43 #include "DOMWindow.h"
45 #include "FloatConversion.h"
46 #include "FloatQuad.h"
47 #include "FloatRect.h"
49 #include "FrameLoader.h"
50 #include "FrameTree.h"
51 #include "FrameView.h"
52 #include "GraphicsContext.h"
53 #include "HTMLFrameOwnerElement.h"
54 #include "HitTestResult.h"
55 #include "InspectorBackend.h"
56 #include "InjectedScriptHost.h"
57 #include "InspectorClient.h"
58 #include "InspectorFrontend.h"
59 #include "InspectorFrontendHost.h"
60 #include "InspectorDatabaseResource.h"
61 #include "InspectorDOMAgent.h"
62 #include "InspectorDOMStorageResource.h"
63 #include "InspectorTimelineAgent.h"
64 #include "InspectorResource.h"
65 #include "JavaScriptProfile.h"
67 #include "ProgressTracker.h"
69 #include "RenderInline.h"
70 #include "ResourceRequest.h"
71 #include "ResourceResponse.h"
72 #include "ScriptCallStack.h"
73 #include "ScriptFunctionCall.h"
74 #include "ScriptObject.h"
75 #include "ScriptString.h"
76 #include "SecurityOrigin.h"
78 #include "SharedBuffer.h"
79 #include "TextEncoding.h"
80 #include "TextIterator.h"
81 #include <wtf/CurrentTime.h>
82 #include <wtf/ListHashSet.h>
83 #include <wtf/RefCounted.h>
84 #include <wtf/StdLibExtras.h>
90 #if ENABLE(DOM_STORAGE)
92 #include "StorageArea.h"
95 #if ENABLE(JAVASCRIPT_DEBUGGER)
96 #include "JavaScriptCallFrame.h"
97 #include "JavaScriptDebugServer.h"
98 #include "JSJavaScriptCallFrame.h"
100 #include <profiler/Profile.h>
101 #include <profiler/Profiler.h>
102 #include <runtime/JSLock.h>
103 #include <runtime/UString.h>
111 static const char* const UserInitiatedProfileName
= "org.webkit.profiles.user-initiated";
112 static const char* const CPUProfileType
= "CPU";
113 static const char* const resourceTrackingEnabledSettingName
= "resourceTrackingEnabled";
114 static const char* const debuggerEnabledSettingName
= "debuggerEnabled";
115 static const char* const profilerEnabledSettingName
= "profilerEnabled";
116 static const char* const inspectorAttachedHeightName
= "inspectorAttachedHeight";
117 static const char* const lastActivePanelSettingName
= "lastActivePanel";
119 static const unsigned defaultAttachedHeight
= 300;
120 static const float minimumAttachedHeight
= 250.0f
;
121 static const float maximumAttachedHeightRatio
= 0.75f
;
123 static unsigned s_inspectorControllerCount
;
125 InspectorController::InspectorController(Page
* page
, InspectorClient
* client
)
126 : m_inspectedPage(page
)
130 , m_windowVisible(false)
131 , m_showAfterVisible(CurrentPanel
)
133 , m_searchingForNode(false)
134 , m_previousMessage(0)
135 , m_resourceTrackingEnabled(false)
136 , m_resourceTrackingSettingsLoaded(false)
137 , m_inspectorBackend(InspectorBackend::create(this))
138 , m_inspectorFrontendHost(InspectorFrontendHost::create(this, client
))
139 , m_injectedScriptHost(InjectedScriptHost::create(this))
140 , m_lastBoundObjectId(1)
141 #if ENABLE(JAVASCRIPT_DEBUGGER)
142 , m_debuggerEnabled(false)
143 , m_attachDebuggerWhenShown(false)
144 , m_profilerEnabled(false)
145 , m_recordingUserInitiatedProfile(false)
146 , m_currentUserInitiatedProfileNumber(-1)
147 , m_nextUserInitiatedProfileNumber(1)
148 , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling
)
151 ASSERT_ARG(page
, page
);
152 ASSERT_ARG(client
, client
);
153 ++s_inspectorControllerCount
;
156 InspectorController::~InspectorController()
158 // These should have been cleared in inspectedPageDestroyed().
160 ASSERT(!m_scriptState
);
161 ASSERT(!m_inspectedPage
);
162 ASSERT(!m_page
|| (m_page
&& !m_page
->parentInspectorController()));
164 deleteAllValues(m_frameResources
);
165 deleteAllValues(m_consoleMessages
);
167 ASSERT(s_inspectorControllerCount
);
168 --s_inspectorControllerCount
;
172 m_inspectorBackend
->disconnectController();
173 m_inspectorFrontendHost
->disconnectController();
174 m_injectedScriptHost
->disconnectController();
177 void InspectorController::inspectedPageDestroyed()
182 ScriptGlobalObject::remove(m_scriptState
, "InspectorBackend");
183 ScriptGlobalObject::remove(m_scriptState
, "InspectorFrontendHost");
184 ScriptGlobalObject::remove(m_scriptState
, "InjectedScriptHost");
186 ASSERT(m_inspectedPage
);
189 m_client
->inspectorDestroyed();
193 bool InspectorController::enabled() const
195 if (!m_inspectedPage
)
197 return m_inspectedPage
->settings()->developerExtrasEnabled();
200 String
InspectorController::setting(const String
& key
) const
202 Settings::iterator it
= m_settings
.find(key
);
203 if (it
!= m_settings
.end())
207 m_client
->populateSetting(key
, &value
);
208 m_settings
.set(key
, value
);
212 void InspectorController::setSetting(const String
& key
, const String
& value
)
214 m_settings
.set(key
, value
);
215 m_client
->storeSetting(key
, value
);
218 // Trying to inspect something in a frame with JavaScript disabled would later lead to
219 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
220 // for now prevent crashes here by never targeting a node in such a frame.
221 static bool canPassNodeToJavaScript(Node
* node
)
225 Frame
* frame
= node
->document()->frame();
226 return frame
&& frame
->script()->isEnabled();
229 void InspectorController::inspect(Node
* node
)
231 if (!canPassNodeToJavaScript(node
) || !enabled())
236 if (node
->nodeType() != Node::ELEMENT_NODE
&& node
->nodeType() != Node::DOCUMENT_NODE
)
237 node
= node
->parentNode();
238 m_nodeToFocus
= node
;
241 m_showAfterVisible
= ElementsPanel
;
248 void InspectorController::focusNode()
254 ASSERT(m_nodeToFocus
);
256 long id
= m_domAgent
->pushNodePathToFrontend(m_nodeToFocus
.get());
257 m_frontend
->updateFocusedNode(id
);
261 void InspectorController::highlight(Node
* node
)
265 ASSERT_ARG(node
, node
);
266 m_highlightedNode
= node
;
267 m_client
->highlight(node
);
270 void InspectorController::hideHighlight()
274 m_highlightedNode
= 0;
275 m_client
->hideHighlight();
278 bool InspectorController::windowVisible()
280 return m_windowVisible
;
283 void InspectorController::setWindowVisible(bool visible
, bool attached
)
285 if (visible
== m_windowVisible
|| !m_frontend
)
288 m_windowVisible
= visible
;
290 if (m_windowVisible
) {
291 setAttachedWindow(attached
);
292 populateScriptObjects();
294 if (m_showAfterVisible
== CurrentPanel
) {
295 String lastActivePanelSetting
= setting(lastActivePanelSettingName
);
296 m_showAfterVisible
= specialPanelForJSName(lastActivePanelSetting
);
301 #if ENABLE(JAVASCRIPT_DEBUGGER)
302 if (m_attachDebuggerWhenShown
)
305 showPanel(m_showAfterVisible
);
307 #if ENABLE(JAVASCRIPT_DEBUGGER)
308 // If the window is being closed with the debugger enabled,
309 // remember this state to re-enable debugger on the next window
311 bool debuggerWasEnabled
= m_debuggerEnabled
;
313 if (debuggerWasEnabled
)
314 m_attachDebuggerWhenShown
= true;
316 if (m_searchingForNode
)
317 toggleSearchForNodeInPage();
318 resetScriptObjects();
319 stopTimelineProfiler();
321 m_showAfterVisible
= CurrentPanel
;
324 void InspectorController::addMessageToConsole(MessageSource source
, MessageType type
, MessageLevel level
, ScriptCallStack
* callStack
)
329 addConsoleMessage(callStack
->state(), new ConsoleMessage(source
, type
, level
, callStack
, m_groupLevel
, type
== TraceMessageType
));
332 void InspectorController::addMessageToConsole(MessageSource source
, MessageType type
, MessageLevel level
, const String
& message
, unsigned lineNumber
, const String
& sourceID
)
337 addConsoleMessage(0, new ConsoleMessage(source
, type
, level
, message
, lineNumber
, sourceID
, m_groupLevel
));
340 void InspectorController::addConsoleMessage(ScriptState
* scriptState
, ConsoleMessage
* consoleMessage
)
343 ASSERT_ARG(consoleMessage
, consoleMessage
);
345 if (m_previousMessage
&& m_previousMessage
->isEqual(scriptState
, consoleMessage
)) {
346 m_previousMessage
->incrementCount();
347 delete consoleMessage
;
349 m_previousMessage
->updateRepeatCountInConsole(m_frontend
.get());
351 m_previousMessage
= consoleMessage
;
352 m_consoleMessages
.append(consoleMessage
);
354 m_previousMessage
->addToConsole(m_frontend
.get());
358 void InspectorController::clearConsoleMessages(bool clearUI
)
360 deleteAllValues(m_consoleMessages
);
361 m_consoleMessages
.clear();
362 m_previousMessage
= 0;
364 releaseWrapperObjectGroup("console");
366 m_domAgent
->releaseDanglingNodes();
367 if (clearUI
&& m_frontend
)
368 m_frontend
->clearConsoleMessages();
371 void InspectorController::startGroup(MessageSource source
, ScriptCallStack
* callStack
)
375 addConsoleMessage(callStack
->state(), new ConsoleMessage(source
, StartGroupMessageType
, LogMessageLevel
, callStack
, m_groupLevel
));
378 void InspectorController::endGroup(MessageSource source
, unsigned lineNumber
, const String
& sourceURL
)
380 if (m_groupLevel
== 0)
385 addConsoleMessage(0, new ConsoleMessage(source
, EndGroupMessageType
, LogMessageLevel
, String(), lineNumber
, sourceURL
, m_groupLevel
));
388 void InspectorController::markTimeline(const String
& message
)
391 timelineAgent()->didMarkTimeline(message
);
394 static unsigned constrainedAttachedWindowHeight(unsigned preferredHeight
, unsigned totalWindowHeight
)
396 return roundf(max(minimumAttachedHeight
, min
<float>(preferredHeight
, totalWindowHeight
* maximumAttachedHeightRatio
)));
399 void InspectorController::attachWindow()
404 unsigned inspectedPageHeight
= m_inspectedPage
->mainFrame()->view()->visibleHeight();
406 m_client
->attachWindow();
408 String attachedHeight
= setting(inspectorAttachedHeightName
);
410 int height
= attachedHeight
.toInt(&success
);
411 unsigned preferredHeight
= success
? height
: defaultAttachedHeight
;
413 // We need to constrain the window height here in case the user has resized the inspected page's window so that
414 // the user's preferred height would be too big to display.
415 m_client
->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight
, inspectedPageHeight
));
418 void InspectorController::detachWindow()
422 m_client
->detachWindow();
425 void InspectorController::setAttachedWindow(bool attached
)
427 if (!enabled() || !m_frontend
)
430 m_frontend
->setAttachedWindow(attached
);
433 void InspectorController::setAttachedWindowHeight(unsigned height
)
438 unsigned totalHeight
= m_page
->mainFrame()->view()->visibleHeight() + m_inspectedPage
->mainFrame()->view()->visibleHeight();
439 unsigned attachedHeight
= constrainedAttachedWindowHeight(height
, totalHeight
);
441 setSetting(inspectorAttachedHeightName
, String::number(attachedHeight
));
443 m_client
->setAttachedWindowHeight(attachedHeight
);
446 void InspectorController::storeLastActivePanel(const String
& panelName
)
448 setSetting(lastActivePanelSettingName
, panelName
);
451 void InspectorController::toggleSearchForNodeInPage()
456 m_searchingForNode
= !m_searchingForNode
;
457 if (!m_searchingForNode
)
461 void InspectorController::mouseDidMoveOverElement(const HitTestResult
& result
, unsigned)
463 if (!enabled() || !m_searchingForNode
)
466 Node
* node
= result
.innerNode();
471 void InspectorController::handleMousePressOnNode(Node
* node
)
476 ASSERT(m_searchingForNode
);
481 // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
485 void InspectorController::inspectedWindowScriptObjectCleared(Frame
* frame
)
487 if (!enabled() || !m_frontend
|| frame
!= m_inspectedPage
->mainFrame())
489 resetInjectedScript();
492 void InspectorController::windowScriptObjectAvailable()
494 if (!m_page
|| !enabled())
497 // Grant the inspector the ability to script the inspected page.
498 m_page
->mainFrame()->document()->securityOrigin()->grantUniversalAccess();
499 m_scriptState
= scriptStateFromPage(debuggerWorld(), m_page
);
500 ScriptGlobalObject::set(m_scriptState
, "InspectorBackend", m_inspectorBackend
.get());
501 ScriptGlobalObject::set(m_scriptState
, "InspectorFrontendHost", m_inspectorFrontendHost
.get());
502 ScriptGlobalObject::set(m_scriptState
, "InjectedScriptHost", m_injectedScriptHost
.get());
505 void InspectorController::scriptObjectReady()
507 ASSERT(m_scriptState
);
511 ScriptObject webInspectorObj
;
512 if (!ScriptGlobalObject::get(m_scriptState
, "WebInspector", webInspectorObj
))
514 ScriptObject injectedScriptObj
;
515 if (!ScriptGlobalObject::get(m_scriptState
, "InjectedScript", injectedScriptObj
))
517 setFrontendProxyObject(m_scriptState
, webInspectorObj
, injectedScriptObj
);
519 #if ENABLE(JAVASCRIPT_DEBUGGER)
520 String debuggerEnabled
= setting(debuggerEnabledSettingName
);
521 if (debuggerEnabled
== "true")
523 String profilerEnabled
= setting(profilerEnabledSettingName
);
524 if (profilerEnabled
== "true")
528 // Make sure our window is visible now that the page loaded
531 m_client
->inspectorWindowObjectCleared();
534 void InspectorController::setFrontendProxyObject(ScriptState
* scriptState
, ScriptObject webInspectorObj
, ScriptObject injectedScriptObj
)
536 m_scriptState
= scriptState
;
537 m_injectedScriptObj
= injectedScriptObj
;
538 m_frontend
.set(new InspectorFrontend(this, scriptState
, webInspectorObj
));
540 m_domAgent
= InspectorDOMAgent::create(m_frontend
.get());
542 m_timelineAgent
->resetFrontendProxyObject(m_frontend
.get());
545 void InspectorController::show()
552 return; // We are using custom frontend - no need to create page.
554 m_page
= m_client
->createPage();
557 m_page
->setParentInspectorController(this);
559 // showWindow() will be called after the page loads in scriptObjectReady()
566 void InspectorController::showPanel(SpecialPanels panel
)
574 m_showAfterVisible
= panel
;
578 if (panel
== CurrentPanel
)
581 m_frontend
->showPanel(panel
);
584 void InspectorController::close()
589 #if ENABLE(JAVASCRIPT_DEBUGGER)
590 stopUserInitiatedProfiling();
595 m_injectedScriptObj
= ScriptObject();
601 if (!m_page
->mainFrame() || !m_page
->mainFrame()->loader() || !m_page
->mainFrame()->loader()->isLoading()) {
602 m_page
->setParentInspectorController(0);
608 void InspectorController::showWindow()
612 unsigned inspectedPageHeight
= m_inspectedPage
->mainFrame()->view()->visibleHeight();
614 m_client
->showWindow();
616 String attachedHeight
= setting(inspectorAttachedHeightName
);
618 int height
= attachedHeight
.toInt(&success
);
619 unsigned preferredHeight
= success
? height
: defaultAttachedHeight
;
621 // This call might not go through (if the window starts out detached), but if the window is initially created attached,
622 // InspectorController::attachWindow is never called, so we need to make sure to set the attachedWindowHeight.
623 // FIXME: Clean up code so we only have to call setAttachedWindowHeight in InspectorController::attachWindow
624 m_client
->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight
, inspectedPageHeight
));
627 void InspectorController::closeWindow()
629 m_client
->closeWindow();
632 void InspectorController::releaseDOMAgent()
634 // m_domAgent is RefPtr. Remove DOM listeners first to ensure that there are
635 // no references to the DOM agent from the DOM tree.
641 void InspectorController::populateScriptObjects()
647 m_domAgent
->setDocument(m_inspectedPage
->mainFrame()->document());
649 ResourcesMap::iterator resourcesEnd
= m_resources
.end();
650 for (ResourcesMap::iterator it
= m_resources
.begin(); it
!= resourcesEnd
; ++it
)
651 it
->second
->createScriptObject(m_frontend
.get());
653 unsigned messageCount
= m_consoleMessages
.size();
654 for (unsigned i
= 0; i
< messageCount
; ++i
)
655 m_consoleMessages
[i
]->addToConsole(m_frontend
.get());
658 DatabaseResourcesMap::iterator databasesEnd
= m_databaseResources
.end();
659 for (DatabaseResourcesMap::iterator it
= m_databaseResources
.begin(); it
!= databasesEnd
; ++it
)
660 it
->second
->bind(m_frontend
.get());
662 #if ENABLE(DOM_STORAGE)
663 DOMStorageResourcesMap::iterator domStorageEnd
= m_domStorageResources
.end();
664 for (DOMStorageResourcesMap::iterator it
= m_domStorageResources
.begin(); it
!= domStorageEnd
; ++it
)
665 it
->second
->bind(m_frontend
.get());
668 m_frontend
->populateInterface();
670 // Dispatch pending frontend commands
671 for (Vector
<pair
<long, String
> >::iterator it
= m_pendingEvaluateTestCommands
.begin(); it
!= m_pendingEvaluateTestCommands
.end(); ++it
)
672 m_frontend
->evaluateForTestInFrontend((*it
).first
, (*it
).second
);
673 m_pendingEvaluateTestCommands
.clear();
676 void InspectorController::resetScriptObjects()
681 ResourcesMap::iterator resourcesEnd
= m_resources
.end();
682 for (ResourcesMap::iterator it
= m_resources
.begin(); it
!= resourcesEnd
; ++it
)
683 it
->second
->releaseScriptObject(m_frontend
.get(), false);
686 DatabaseResourcesMap::iterator databasesEnd
= m_databaseResources
.end();
687 for (DatabaseResourcesMap::iterator it
= m_databaseResources
.begin(); it
!= databasesEnd
; ++it
)
688 it
->second
->unbind();
690 #if ENABLE(DOM_STORAGE)
691 DOMStorageResourcesMap::iterator domStorageEnd
= m_domStorageResources
.end();
692 for (DOMStorageResourcesMap::iterator it
= m_domStorageResources
.begin(); it
!= domStorageEnd
; ++it
)
693 it
->second
->unbind();
697 m_timelineAgent
->reset();
701 m_objectGroups
.clear();
702 m_idToWrappedObject
.clear();
705 void InspectorController::pruneResources(ResourcesMap
* resourceMap
, DocumentLoader
* loaderToKeep
)
707 ASSERT_ARG(resourceMap
, resourceMap
);
709 ResourcesMap
mapCopy(*resourceMap
);
710 ResourcesMap::iterator end
= mapCopy
.end();
711 for (ResourcesMap::iterator it
= mapCopy
.begin(); it
!= end
; ++it
) {
712 InspectorResource
* resource
= (*it
).second
.get();
713 if (resource
== m_mainResource
)
716 if (!loaderToKeep
|| !resource
->isSameLoader(loaderToKeep
)) {
717 removeResource(resource
);
719 resource
->releaseScriptObject(m_frontend
.get(), true);
724 void InspectorController::didCommitLoad(DocumentLoader
* loader
)
729 ASSERT(m_inspectedPage
);
731 if (loader
->frame() == m_inspectedPage
->mainFrame()) {
732 m_client
->inspectedURLChanged(loader
->url().string());
734 clearConsoleMessages(false);
738 #if ENABLE(JAVASCRIPT_DEBUGGER)
740 m_currentUserInitiatedProfileNumber
= 1;
741 m_nextUserInitiatedProfileNumber
= 1;
743 // resetScriptObjects should be called before database and DOM storage
744 // resources are cleared so that it has a chance to unbind them.
745 resetScriptObjects();
748 m_databaseResources
.clear();
750 #if ENABLE(DOM_STORAGE)
751 m_domStorageResources
.clear();
755 if (!loader
->frameLoader()->isLoadingFromCachedPage()) {
756 ASSERT(m_mainResource
&& m_mainResource
->isSameLoader(loader
));
757 // We don't add the main resource until its load is committed. This is
758 // needed to keep the load for a user-entered URL from showing up in the
759 // list of resources for the page they are navigating away from.
761 m_mainResource
->createScriptObject(m_frontend
.get());
763 // Pages loaded from the page cache are committed before
764 // m_mainResource is the right resource for this load, so we
765 // clear it here. It will be re-assigned in
766 // identifierForInitialRequest.
769 if (windowVisible()) {
770 m_frontend
->didCommitLoad();
771 m_domAgent
->setDocument(m_inspectedPage
->mainFrame()->document());
776 for (Frame
* frame
= loader
->frame(); frame
; frame
= frame
->tree()->traverseNext(loader
->frame()))
777 if (ResourcesMap
* resourceMap
= m_frameResources
.get(frame
))
778 pruneResources(resourceMap
, loader
);
781 void InspectorController::frameDetachedFromParent(Frame
* frame
)
785 if (ResourcesMap
* resourceMap
= m_frameResources
.get(frame
))
786 removeAllResources(resourceMap
);
789 void InspectorController::addResource(InspectorResource
* resource
)
791 m_resources
.set(resource
->identifier(), resource
);
792 m_knownResources
.add(resource
->requestURL());
794 Frame
* frame
= resource
->frame();
795 ResourcesMap
* resourceMap
= m_frameResources
.get(frame
);
797 resourceMap
->set(resource
->identifier(), resource
);
799 resourceMap
= new ResourcesMap
;
800 resourceMap
->set(resource
->identifier(), resource
);
801 m_frameResources
.set(frame
, resourceMap
);
805 void InspectorController::removeResource(InspectorResource
* resource
)
807 m_resources
.remove(resource
->identifier());
808 String requestURL
= resource
->requestURL();
809 if (!requestURL
.isNull())
810 m_knownResources
.remove(requestURL
);
812 Frame
* frame
= resource
->frame();
813 ResourcesMap
* resourceMap
= m_frameResources
.get(frame
);
815 ASSERT_NOT_REACHED();
819 resourceMap
->remove(resource
->identifier());
820 if (resourceMap
->isEmpty()) {
821 m_frameResources
.remove(frame
);
826 InspectorResource
* InspectorController::getTrackedResource(unsigned long identifier
)
831 if (m_resourceTrackingEnabled
)
832 return m_resources
.get(identifier
).get();
834 bool isMainResource
= m_mainResource
&& m_mainResource
->identifier() == identifier
;
836 return m_mainResource
.get();
841 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader
* loader
, const CachedResource
* cachedResource
)
846 // If the resource URL is already known, we don't need to add it again since this is just a cached load.
847 if (m_knownResources
.contains(cachedResource
->url()))
850 ASSERT(m_inspectedPage
);
851 bool isMainResource
= isMainResourceLoader(loader
, KURL(ParsedURLString
, cachedResource
->url()));
852 ensureResourceTrackingSettingsLoaded();
853 if (!isMainResource
&& !m_resourceTrackingEnabled
)
856 RefPtr
<InspectorResource
> resource
= InspectorResource::createCached(m_inspectedPage
->progress()->createUniqueIdentifier() , loader
, cachedResource
);
858 if (isMainResource
) {
859 m_mainResource
= resource
;
860 resource
->markMainResource();
863 addResource(resource
.get());
866 resource
->createScriptObject(m_frontend
.get());
869 void InspectorController::identifierForInitialRequest(unsigned long identifier
, DocumentLoader
* loader
, const ResourceRequest
& request
)
873 ASSERT(m_inspectedPage
);
875 bool isMainResource
= isMainResourceLoader(loader
, request
.url());
876 ensureResourceTrackingSettingsLoaded();
877 if (!isMainResource
&& !m_resourceTrackingEnabled
)
880 RefPtr
<InspectorResource
> resource
= InspectorResource::create(identifier
, loader
);
882 resource
->updateRequest(request
);
884 if (isMainResource
) {
885 m_mainResource
= resource
;
886 resource
->markMainResource();
889 addResource(resource
.get());
891 if (windowVisible() && loader
->frameLoader()->isLoadingFromCachedPage() && resource
== m_mainResource
)
892 resource
->createScriptObject(m_frontend
.get());
895 void InspectorController::mainResourceFiredDOMContentEvent(DocumentLoader
* loader
, const KURL
& url
)
897 if (!enabled() || !isMainResourceLoader(loader
, url
))
900 if (m_mainResource
) {
901 m_mainResource
->markDOMContentEventTime();
903 m_mainResource
->updateScriptObject(m_frontend
.get());
907 void InspectorController::mainResourceFiredLoadEvent(DocumentLoader
* loader
, const KURL
& url
)
909 if (!enabled() || !isMainResourceLoader(loader
, url
))
912 if (m_mainResource
) {
913 m_mainResource
->markLoadEventTime();
915 m_mainResource
->updateScriptObject(m_frontend
.get());
919 bool InspectorController::isMainResourceLoader(DocumentLoader
* loader
, const KURL
& requestUrl
)
921 return loader
->frame() == m_inspectedPage
->mainFrame() && requestUrl
== loader
->requestURL();
924 void InspectorController::willSendRequest(unsigned long identifier
, const ResourceRequest
& request
, const ResourceResponse
& redirectResponse
)
926 bool isMainResource
= (m_mainResource
&& m_mainResource
->identifier() == identifier
);
928 m_timelineAgent
->willSendResourceRequest(identifier
, isMainResource
, request
);
930 RefPtr
<InspectorResource
> resource
= getTrackedResource(identifier
);
934 resource
->startTiming();
936 if (!redirectResponse
.isNull()) {
937 resource
->updateRequest(request
);
938 resource
->updateResponse(redirectResponse
);
941 if (resource
!= m_mainResource
&& windowVisible())
942 resource
->createScriptObject(m_frontend
.get());
945 void InspectorController::didReceiveResponse(unsigned long identifier
, const ResourceResponse
& response
)
948 m_timelineAgent
->didReceiveResourceResponse(identifier
, response
);
950 RefPtr
<InspectorResource
> resource
= getTrackedResource(identifier
);
954 resource
->updateResponse(response
);
955 resource
->markResponseReceivedTime();
958 resource
->updateScriptObject(m_frontend
.get());
961 void InspectorController::didReceiveContentLength(unsigned long identifier
, int lengthReceived
)
963 RefPtr
<InspectorResource
> resource
= getTrackedResource(identifier
);
967 resource
->addLength(lengthReceived
);
970 resource
->updateScriptObject(m_frontend
.get());
973 void InspectorController::didFinishLoading(unsigned long identifier
)
976 m_timelineAgent
->didFinishLoadingResource(identifier
, false);
978 RefPtr
<InspectorResource
> resource
= getTrackedResource(identifier
);
982 removeResource(resource
.get());
984 resource
->endTiming();
986 addResource(resource
.get());
989 resource
->updateScriptObject(m_frontend
.get());
992 void InspectorController::didFailLoading(unsigned long identifier
, const ResourceError
& /*error*/)
995 m_timelineAgent
->didFinishLoadingResource(identifier
, true);
997 RefPtr
<InspectorResource
> resource
= getTrackedResource(identifier
);
1001 removeResource(resource
.get());
1003 resource
->markFailed();
1004 resource
->endTiming();
1006 addResource(resource
.get());
1008 if (windowVisible())
1009 resource
->updateScriptObject(m_frontend
.get());
1012 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier
, const ScriptString
& sourceString
)
1014 if (!enabled() || !m_resourceTrackingEnabled
)
1017 InspectorResource
* resource
= m_resources
.get(identifier
).get();
1021 resource
->setXMLHttpResponseText(sourceString
);
1023 if (windowVisible())
1024 resource
->updateScriptObject(m_frontend
.get());
1027 void InspectorController::scriptImported(unsigned long identifier
, const String
& sourceString
)
1029 if (!enabled() || !m_resourceTrackingEnabled
)
1032 InspectorResource
* resource
= m_resources
.get(identifier
).get();
1036 // FIXME: imported script and XHR response are currently viewed as the same
1037 // thing by the Inspector. They should be made into distinct types.
1038 resource
->setXMLHttpResponseText(ScriptString(sourceString
));
1040 if (windowVisible())
1041 resource
->updateScriptObject(m_frontend
.get());
1044 void InspectorController::enableResourceTracking(bool always
, bool reload
)
1050 setSetting(resourceTrackingEnabledSettingName
, "true");
1052 if (m_resourceTrackingEnabled
)
1055 ASSERT(m_inspectedPage
);
1056 m_resourceTrackingEnabled
= true;
1058 m_frontend
->resourceTrackingWasEnabled();
1061 m_inspectedPage
->mainFrame()->loader()->reload();
1064 void InspectorController::disableResourceTracking(bool always
)
1070 setSetting(resourceTrackingEnabledSettingName
, "false");
1072 ASSERT(m_inspectedPage
);
1073 m_resourceTrackingEnabled
= false;
1075 m_frontend
->resourceTrackingWasDisabled();
1078 void InspectorController::ensureResourceTrackingSettingsLoaded()
1080 if (m_resourceTrackingSettingsLoaded
)
1082 m_resourceTrackingSettingsLoaded
= true;
1084 String resourceTracking
= setting(resourceTrackingEnabledSettingName
);
1085 if (resourceTracking
== "true")
1086 m_resourceTrackingEnabled
= true;
1089 void InspectorController::startTimelineProfiler()
1094 if (m_timelineAgent
)
1097 m_timelineAgent
= new InspectorTimelineAgent(m_frontend
.get());
1099 m_frontend
->timelineProfilerWasStarted();
1102 void InspectorController::stopTimelineProfiler()
1107 if (!m_timelineAgent
)
1110 m_timelineAgent
= 0;
1112 m_frontend
->timelineProfilerWasStopped();
1115 #if ENABLE(DATABASE)
1116 void InspectorController::selectDatabase(Database
* database
)
1121 for (DatabaseResourcesMap::iterator it
= m_databaseResources
.begin(); it
!= m_databaseResources
.end(); ++it
) {
1122 if (it
->second
->database() == database
) {
1123 m_frontend
->selectDatabase(it
->first
);
1129 Database
* InspectorController::databaseForId(int databaseId
)
1131 DatabaseResourcesMap::iterator it
= m_databaseResources
.find(databaseId
);
1132 if (it
== m_databaseResources
.end())
1134 return it
->second
->database();
1137 void InspectorController::didOpenDatabase(Database
* database
, const String
& domain
, const String
& name
, const String
& version
)
1142 RefPtr
<InspectorDatabaseResource
> resource
= InspectorDatabaseResource::create(database
, domain
, name
, version
);
1144 m_databaseResources
.set(resource
->id(), resource
);
1146 // Resources are only bound while visible.
1147 if (windowVisible())
1148 resource
->bind(m_frontend
.get());
1152 void InspectorController::getCookies(long callId
)
1157 // If we can get raw cookies.
1158 ListHashSet
<Cookie
> rawCookiesList
;
1160 // If we can't get raw cookies - fall back to String representation
1161 String stringCookiesList
;
1163 // Return value to getRawCookies should be the same for every call because
1164 // the return value is platform/network backend specific, and the call will
1165 // always return the same true/false value.
1166 bool rawCookiesImplemented
= false;
1168 ResourcesMap::iterator resourcesEnd
= m_resources
.end();
1169 for (ResourcesMap::iterator it
= m_resources
.begin(); it
!= resourcesEnd
; ++it
) {
1170 Document
* document
= it
->second
->frame()->document();
1171 Vector
<Cookie
> docCookiesList
;
1172 rawCookiesImplemented
= getRawCookies(document
, document
->cookieURL(), docCookiesList
);
1174 if (!rawCookiesImplemented
) {
1175 // FIXME: We need duplication checking for the String representation of cookies.
1176 ExceptionCode ec
= 0;
1177 stringCookiesList
+= document
->cookie(ec
);
1178 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
1179 // because "document" is the document of the main frame of the page.
1182 int cookiesSize
= docCookiesList
.size();
1183 for (int i
= 0; i
< cookiesSize
; i
++) {
1184 if (!rawCookiesList
.contains(docCookiesList
[i
]))
1185 rawCookiesList
.add(docCookiesList
[i
]);
1190 if (!rawCookiesImplemented
)
1191 m_frontend
->didGetCookies(callId
, m_frontend
->newScriptArray(), stringCookiesList
);
1193 m_frontend
->didGetCookies(callId
, buildArrayForCookies(rawCookiesList
), String());
1196 ScriptArray
InspectorController::buildArrayForCookies(ListHashSet
<Cookie
>& cookiesList
)
1198 ScriptArray cookies
= m_frontend
->newScriptArray();
1200 ListHashSet
<Cookie
>::iterator end
= cookiesList
.end();
1201 ListHashSet
<Cookie
>::iterator it
= cookiesList
.begin();
1202 for (int i
= 0; it
!= end
; ++it
, i
++)
1203 cookies
.set(i
, buildObjectForCookie(*it
));
1208 ScriptObject
InspectorController::buildObjectForCookie(const Cookie
& cookie
)
1210 ScriptObject value
= m_frontend
->newScriptObject();
1211 value
.set("name", cookie
.name
);
1212 value
.set("value", cookie
.value
);
1213 value
.set("domain", cookie
.domain
);
1214 value
.set("path", cookie
.path
);
1215 value
.set("expires", cookie
.expires
);
1216 value
.set("size", (cookie
.name
.length() + cookie
.value
.length()));
1217 value
.set("httpOnly", cookie
.httpOnly
);
1218 value
.set("secure", cookie
.secure
);
1219 value
.set("session", cookie
.session
);
1223 #if ENABLE(DOM_STORAGE)
1224 void InspectorController::didUseDOMStorage(StorageArea
* storageArea
, bool isLocalStorage
, Frame
* frame
)
1229 DOMStorageResourcesMap::iterator domStorageEnd
= m_domStorageResources
.end();
1230 for (DOMStorageResourcesMap::iterator it
= m_domStorageResources
.begin(); it
!= domStorageEnd
; ++it
)
1231 if (it
->second
->isSameHostAndType(frame
, isLocalStorage
))
1234 RefPtr
<Storage
> domStorage
= Storage::create(frame
, storageArea
);
1235 RefPtr
<InspectorDOMStorageResource
> resource
= InspectorDOMStorageResource::create(domStorage
.get(), isLocalStorage
, frame
);
1237 m_domStorageResources
.set(resource
->id(), resource
);
1239 // Resources are only bound while visible.
1240 if (windowVisible())
1241 resource
->bind(m_frontend
.get());
1244 void InspectorController::selectDOMStorage(Storage
* storage
)
1250 Frame
* frame
= storage
->frame();
1251 bool isLocalStorage
= (frame
->domWindow()->localStorage() == storage
);
1252 int storageResourceId
= 0;
1253 DOMStorageResourcesMap::iterator domStorageEnd
= m_domStorageResources
.end();
1254 for (DOMStorageResourcesMap::iterator it
= m_domStorageResources
.begin(); it
!= domStorageEnd
; ++it
) {
1255 if (it
->second
->isSameHostAndType(frame
, isLocalStorage
)) {
1256 storageResourceId
= it
->first
;
1260 if (storageResourceId
)
1261 m_frontend
->selectDOMStorage(storageResourceId
);
1264 void InspectorController::getDOMStorageEntries(int callId
, int storageId
)
1269 ScriptArray jsonArray
= m_frontend
->newScriptArray();
1270 InspectorDOMStorageResource
* storageResource
= getDOMStorageResourceForId(storageId
);
1271 if (storageResource
) {
1272 storageResource
->startReportingChangesToFrontend();
1273 Storage
* domStorage
= storageResource
->domStorage();
1274 for (unsigned i
= 0; i
< domStorage
->length(); ++i
) {
1275 String
name(domStorage
->key(i
));
1276 String
value(domStorage
->getItem(name
));
1277 ScriptArray entry
= m_frontend
->newScriptArray();
1279 entry
.set(1, value
);
1280 jsonArray
.set(i
, entry
);
1283 m_frontend
->didGetDOMStorageEntries(callId
, jsonArray
);
1286 void InspectorController::setDOMStorageItem(long callId
, long storageId
, const String
& key
, const String
& value
)
1291 bool success
= false;
1292 InspectorDOMStorageResource
* storageResource
= getDOMStorageResourceForId(storageId
);
1293 if (storageResource
) {
1294 ExceptionCode exception
= 0;
1295 storageResource
->domStorage()->setItem(key
, value
, exception
);
1296 success
= (exception
== 0);
1298 m_frontend
->didSetDOMStorageItem(callId
, success
);
1301 void InspectorController::removeDOMStorageItem(long callId
, long storageId
, const String
& key
)
1306 bool success
= false;
1307 InspectorDOMStorageResource
* storageResource
= getDOMStorageResourceForId(storageId
);
1308 if (storageResource
) {
1309 storageResource
->domStorage()->removeItem(key
);
1312 m_frontend
->didRemoveDOMStorageItem(callId
, success
);
1315 InspectorDOMStorageResource
* InspectorController::getDOMStorageResourceForId(int storageId
)
1317 DOMStorageResourcesMap::iterator it
= m_domStorageResources
.find(storageId
);
1318 if (it
== m_domStorageResources
.end())
1320 return it
->second
.get();
1324 void InspectorController::moveWindowBy(float x
, float y
) const
1326 if (!m_page
|| !enabled())
1329 FloatRect frameRect
= m_page
->chrome()->windowRect();
1330 frameRect
.move(x
, y
);
1331 m_page
->chrome()->setWindowRect(frameRect
);
1334 #if ENABLE(JAVASCRIPT_DEBUGGER)
1335 void InspectorController::addProfile(PassRefPtr
<Profile
> prpProfile
, unsigned lineNumber
, const UString
& sourceURL
)
1340 RefPtr
<Profile
> profile
= prpProfile
;
1341 m_profiles
.add(profile
->uid(), profile
);
1344 JSLock
lock(SilenceAssertionsOnly
);
1345 m_frontend
->addProfileHeader(createProfileHeader(*profile
));
1348 addProfileFinishedMessageToConsole(profile
, lineNumber
, sourceURL
);
1351 void InspectorController::addProfileFinishedMessageToConsole(PassRefPtr
<Profile
> prpProfile
, unsigned lineNumber
, const UString
& sourceURL
)
1353 RefPtr
<Profile
> profile
= prpProfile
;
1355 UString message
= "Profile \"webkit-profile://";
1356 message
+= encodeWithURLEscapeSequences(CPUProfileType
);
1358 message
+= encodeWithURLEscapeSequences(profile
->title());
1360 message
+= UString::from(profile
->uid());
1361 message
+= "\" finished.";
1362 addMessageToConsole(JSMessageSource
, LogMessageType
, LogMessageLevel
, message
, lineNumber
, sourceURL
);
1365 void InspectorController::addStartProfilingMessageToConsole(const UString
& title
, unsigned lineNumber
, const UString
& sourceURL
)
1367 UString message
= "Profile \"webkit-profile://";
1368 message
+= encodeWithURLEscapeSequences(CPUProfileType
);
1370 message
+= encodeWithURLEscapeSequences(title
);
1371 message
+= "#0\" started.";
1372 addMessageToConsole(JSMessageSource
, LogMessageType
, LogMessageLevel
, message
, lineNumber
, sourceURL
);
1375 void InspectorController::getProfileHeaders(long callId
)
1379 ScriptArray result
= m_frontend
->newScriptArray();
1380 ProfilesMap::iterator profilesEnd
= m_profiles
.end();
1382 for (ProfilesMap::iterator it
= m_profiles
.begin(); it
!= profilesEnd
; ++it
)
1383 result
.set(i
++, createProfileHeader(*it
->second
));
1384 m_frontend
->didGetProfileHeaders(callId
, result
);
1387 void InspectorController::getProfile(long callId
, unsigned uid
)
1391 ProfilesMap::iterator it
= m_profiles
.find(uid
);
1392 if (it
!= m_profiles
.end())
1393 m_frontend
->didGetProfile(callId
, toJS(m_scriptState
, it
->second
.get()));
1396 ScriptObject
InspectorController::createProfileHeader(const JSC::Profile
& profile
)
1398 ScriptObject header
= m_frontend
->newScriptObject();
1399 header
.set("title", profile
.title());
1400 header
.set("uid", profile
.uid());
1401 header
.set("typeId", UString(CPUProfileType
));
1405 UString
InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber
= false)
1407 if (incrementProfileNumber
)
1408 m_currentUserInitiatedProfileNumber
= m_nextUserInitiatedProfileNumber
++;
1410 UString title
= UserInitiatedProfileName
;
1412 title
+= UString::from(m_currentUserInitiatedProfileNumber
);
1417 void InspectorController::startUserInitiatedProfilingSoon()
1419 m_startProfiling
.startOneShot(0);
1422 void InspectorController::startUserInitiatedProfiling(Timer
<InspectorController
>*)
1427 if (!profilerEnabled()) {
1428 enableProfiler(false, true);
1429 JavaScriptDebugServer::shared().recompileAllJSFunctions();
1432 m_recordingUserInitiatedProfile
= true;
1434 UString title
= getCurrentUserInitiatedProfileName(true);
1436 ExecState
* scriptState
= toJSDOMWindow(m_inspectedPage
->mainFrame(), debuggerWorld())->globalExec();
1437 Profiler::profiler()->startProfiling(scriptState
, title
);
1439 addStartProfilingMessageToConsole(title
, 0, UString());
1441 toggleRecordButton(true);
1444 void InspectorController::stopUserInitiatedProfiling()
1449 m_recordingUserInitiatedProfile
= false;
1451 UString title
= getCurrentUserInitiatedProfileName();
1453 ExecState
* scriptState
= toJSDOMWindow(m_inspectedPage
->mainFrame(), debuggerWorld())->globalExec();
1454 RefPtr
<Profile
> profile
= Profiler::profiler()->stopProfiling(scriptState
, title
);
1456 addProfile(profile
, 0, UString());
1458 toggleRecordButton(false);
1461 void InspectorController::toggleRecordButton(bool isProfiling
)
1465 m_frontend
->setRecordingProfile(isProfiling
);
1468 void InspectorController::enableProfiler(bool always
, bool skipRecompile
)
1471 setSetting(profilerEnabledSettingName
, "true");
1473 if (m_profilerEnabled
)
1476 m_profilerEnabled
= true;
1479 JavaScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1482 m_frontend
->profilerWasEnabled();
1485 void InspectorController::disableProfiler(bool always
)
1488 setSetting(profilerEnabledSettingName
, "false");
1490 if (!m_profilerEnabled
)
1493 m_profilerEnabled
= false;
1495 JavaScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1498 m_frontend
->profilerWasDisabled();
1501 void InspectorController::enableDebuggerFromFrontend(bool always
)
1504 setSetting(debuggerEnabledSettingName
, "true");
1506 ASSERT(m_inspectedPage
);
1508 JavaScriptDebugServer::shared().addListener(this, m_inspectedPage
);
1509 JavaScriptDebugServer::shared().clearBreakpoints();
1511 m_debuggerEnabled
= true;
1512 m_frontend
->debuggerWasEnabled();
1515 void InspectorController::enableDebugger()
1520 if (m_debuggerEnabled
)
1523 if (!m_scriptState
|| !m_frontend
) {
1524 m_attachDebuggerWhenShown
= true;
1526 m_frontend
->attachDebuggerWhenShown();
1527 m_attachDebuggerWhenShown
= false;
1531 void InspectorController::disableDebugger(bool always
)
1537 setSetting(debuggerEnabledSettingName
, "false");
1539 ASSERT(m_inspectedPage
);
1541 JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage
);
1543 m_debuggerEnabled
= false;
1544 m_attachDebuggerWhenShown
= false;
1547 m_frontend
->debuggerWasDisabled();
1550 void InspectorController::resumeDebugger()
1552 if (!m_debuggerEnabled
)
1554 JavaScriptDebugServer::shared().continueProgram();
1557 // JavaScriptDebugListener functions
1559 void InspectorController::didParseSource(ExecState
*, const SourceCode
& source
)
1561 m_frontend
->parsedScriptSource(source
);
1564 void InspectorController::failedToParseSource(ExecState
*, const SourceCode
& source
, int errorLine
, const UString
& errorMessage
)
1566 m_frontend
->failedToParseScriptSource(source
, errorLine
, errorMessage
);
1569 void InspectorController::didPause()
1571 ScriptFunctionCall
function(m_scriptState
, m_injectedScriptObj
, "getCallFrames");
1572 ScriptValue callFrames
= function
.call();
1573 m_frontend
->pausedScript(callFrames
);
1576 void InspectorController::didContinue()
1578 m_frontend
->resumedScript();
1583 void InspectorController::evaluateForTestInFrontend(long callId
, const String
& script
)
1586 m_frontend
->evaluateForTestInFrontend(callId
, script
);
1588 m_pendingEvaluateTestCommands
.append(pair
<long, String
>(callId
, script
));
1591 void InspectorController::didEvaluateForTestInFrontend(long callId
, const String
& jsonResult
)
1593 ScriptState
* scriptState
= scriptStateFromPage(debuggerWorld(), m_inspectedPage
);
1594 ScriptObject window
;
1595 ScriptGlobalObject::get(scriptState
, "window", window
);
1596 ScriptFunctionCall
function(scriptState
, window
, "didEvaluateForTestInFrontend");
1597 function
.appendArgument(callId
);
1598 function
.appendArgument(jsonResult
);
1602 static Path
quadToPath(const FloatQuad
& quad
)
1605 quadPath
.moveTo(quad
.p1());
1606 quadPath
.addLineTo(quad
.p2());
1607 quadPath
.addLineTo(quad
.p3());
1608 quadPath
.addLineTo(quad
.p4());
1609 quadPath
.closeSubpath();
1613 static void drawOutlinedQuad(GraphicsContext
& context
, const FloatQuad
& quad
, const Color
& fillColor
)
1615 static const int outlineThickness
= 2;
1616 static const Color
outlineColor(62, 86, 180, 228);
1618 Path quadPath
= quadToPath(quad
);
1620 // Clip out the quad, then draw with a 2px stroke to get a pixel
1621 // of outline (because inflating a quad is hard)
1624 context
.addPath(quadPath
);
1625 context
.clipOut(quadPath
);
1627 context
.addPath(quadPath
);
1628 context
.setStrokeThickness(outlineThickness
);
1629 context
.setStrokeColor(outlineColor
, DeviceColorSpace
);
1630 context
.strokePath();
1636 context
.addPath(quadPath
);
1637 context
.setFillColor(fillColor
, DeviceColorSpace
);
1641 static void drawOutlinedQuadWithClip(GraphicsContext
& context
, const FloatQuad
& quad
, const FloatQuad
& clipQuad
, const Color
& fillColor
)
1644 Path clipQuadPath
= quadToPath(clipQuad
);
1645 context
.clipOut(clipQuadPath
);
1646 drawOutlinedQuad(context
, quad
, fillColor
);
1650 static void drawHighlightForBox(GraphicsContext
& context
, const FloatQuad
& contentQuad
, const FloatQuad
& paddingQuad
, const FloatQuad
& borderQuad
, const FloatQuad
& marginQuad
)
1652 static const Color
contentBoxColor(125, 173, 217, 128);
1653 static const Color
paddingBoxColor(125, 173, 217, 160);
1654 static const Color
borderBoxColor(125, 173, 217, 192);
1655 static const Color
marginBoxColor(125, 173, 217, 228);
1657 if (marginQuad
!= borderQuad
)
1658 drawOutlinedQuadWithClip(context
, marginQuad
, borderQuad
, marginBoxColor
);
1659 if (borderQuad
!= paddingQuad
)
1660 drawOutlinedQuadWithClip(context
, borderQuad
, paddingQuad
, borderBoxColor
);
1661 if (paddingQuad
!= contentQuad
)
1662 drawOutlinedQuadWithClip(context
, paddingQuad
, contentQuad
, paddingBoxColor
);
1664 drawOutlinedQuad(context
, contentQuad
, contentBoxColor
);
1667 static void drawHighlightForLineBoxes(GraphicsContext
& context
, const Vector
<FloatQuad
>& lineBoxQuads
)
1669 static const Color
lineBoxColor(125, 173, 217, 128);
1671 for (size_t i
= 0; i
< lineBoxQuads
.size(); ++i
)
1672 drawOutlinedQuad(context
, lineBoxQuads
[i
], lineBoxColor
);
1675 static inline void convertFromFrameToMainFrame(Frame
* frame
, IntRect
& rect
)
1677 rect
= frame
->page()->mainFrame()->view()->windowToContents(frame
->view()->contentsToWindow(rect
));
1680 static inline IntSize
frameToMainFrameOffset(Frame
* frame
)
1682 IntPoint mainFramePoint
= frame
->page()->mainFrame()->view()->windowToContents(frame
->view()->contentsToWindow(IntPoint()));
1683 return mainFramePoint
- IntPoint();
1686 void InspectorController::drawNodeHighlight(GraphicsContext
& context
) const
1688 if (!m_highlightedNode
)
1691 RenderObject
* renderer
= m_highlightedNode
->renderer();
1692 Frame
* containingFrame
= m_highlightedNode
->document()->frame();
1693 if (!renderer
|| !containingFrame
)
1696 IntSize mainFrameOffset
= frameToMainFrameOffset(containingFrame
);
1697 IntRect boundingBox
= renderer
->absoluteBoundingBoxRect(true);
1698 boundingBox
.move(mainFrameOffset
);
1700 ASSERT(m_inspectedPage
);
1702 FrameView
* view
= m_inspectedPage
->mainFrame()->view();
1703 FloatRect overlayRect
= view
->visibleContentRect();
1704 if (!overlayRect
.contains(boundingBox
) && !boundingBox
.contains(enclosingIntRect(overlayRect
)))
1705 overlayRect
= view
->visibleContentRect();
1706 context
.translate(-overlayRect
.x(), -overlayRect
.y());
1708 if (renderer
->isBox()) {
1709 RenderBox
* renderBox
= toRenderBox(renderer
);
1711 IntRect contentBox
= renderBox
->contentBoxRect();
1713 IntRect
paddingBox(contentBox
.x() - renderBox
->paddingLeft(), contentBox
.y() - renderBox
->paddingTop(),
1714 contentBox
.width() + renderBox
->paddingLeft() + renderBox
->paddingRight(), contentBox
.height() + renderBox
->paddingTop() + renderBox
->paddingBottom());
1715 IntRect
borderBox(paddingBox
.x() - renderBox
->borderLeft(), paddingBox
.y() - renderBox
->borderTop(),
1716 paddingBox
.width() + renderBox
->borderLeft() + renderBox
->borderRight(), paddingBox
.height() + renderBox
->borderTop() + renderBox
->borderBottom());
1717 IntRect
marginBox(borderBox
.x() - renderBox
->marginLeft(), borderBox
.y() - renderBox
->marginTop(),
1718 borderBox
.width() + renderBox
->marginLeft() + renderBox
->marginRight(), borderBox
.height() + renderBox
->marginTop() + renderBox
->marginBottom());
1720 FloatQuad absContentQuad
= renderBox
->localToAbsoluteQuad(FloatRect(contentBox
));
1721 FloatQuad absPaddingQuad
= renderBox
->localToAbsoluteQuad(FloatRect(paddingBox
));
1722 FloatQuad absBorderQuad
= renderBox
->localToAbsoluteQuad(FloatRect(borderBox
));
1723 FloatQuad absMarginQuad
= renderBox
->localToAbsoluteQuad(FloatRect(marginBox
));
1725 absContentQuad
.move(mainFrameOffset
);
1726 absPaddingQuad
.move(mainFrameOffset
);
1727 absBorderQuad
.move(mainFrameOffset
);
1728 absMarginQuad
.move(mainFrameOffset
);
1730 drawHighlightForBox(context
, absContentQuad
, absPaddingQuad
, absBorderQuad
, absMarginQuad
);
1731 } else if (renderer
->isRenderInline()) {
1732 RenderInline
* renderInline
= toRenderInline(renderer
);
1734 // FIXME: We should show margins/padding/border for inlines.
1735 Vector
<FloatQuad
> lineBoxQuads
;
1736 renderInline
->absoluteQuads(lineBoxQuads
);
1737 for (unsigned i
= 0; i
< lineBoxQuads
.size(); ++i
)
1738 lineBoxQuads
[i
] += mainFrameOffset
;
1740 drawHighlightForLineBoxes(context
, lineBoxQuads
);
1744 void InspectorController::count(const String
& title
, unsigned lineNumber
, const String
& sourceID
)
1746 String identifier
= title
+ String::format("@%s:%d", sourceID
.utf8().data(), lineNumber
);
1747 HashMap
<String
, unsigned>::iterator it
= m_counts
.find(identifier
);
1749 if (it
== m_counts
.end())
1752 count
= it
->second
+ 1;
1753 m_counts
.remove(it
);
1756 m_counts
.add(identifier
, count
);
1758 String message
= String::format("%s: %d", title
.utf8().data(), count
);
1759 addMessageToConsole(JSMessageSource
, LogMessageType
, LogMessageLevel
, message
, lineNumber
, sourceID
);
1762 void InspectorController::startTiming(const String
& title
)
1764 m_times
.add(title
, currentTime() * 1000);
1767 bool InspectorController::stopTiming(const String
& title
, double& elapsed
)
1769 HashMap
<String
, double>::iterator it
= m_times
.find(title
);
1770 if (it
== m_times
.end())
1773 double startTime
= it
->second
;
1776 elapsed
= currentTime() * 1000 - startTime
;
1780 InspectorController::SpecialPanels
InspectorController::specialPanelForJSName(const String
& panelName
)
1782 if (panelName
== "elements")
1783 return ElementsPanel
;
1784 else if (panelName
== "resources")
1785 return ResourcesPanel
;
1786 else if (panelName
== "scripts")
1787 return ScriptsPanel
;
1788 else if (panelName
== "timeline")
1789 return TimelinePanel
;
1790 else if (panelName
== "profiles")
1791 return ProfilesPanel
;
1792 else if (panelName
== "storage" || panelName
== "databases")
1793 return StoragePanel
;
1794 else if (panelName
== "console")
1795 return ConsolePanel
;
1797 return ElementsPanel
;
1800 ScriptValue
InspectorController::wrapObject(const ScriptValue
& quarantinedObject
, const String
& objectGroup
)
1802 ScriptFunctionCall
function(m_scriptState
, m_injectedScriptObj
, "createProxyObject");
1803 function
.appendArgument(quarantinedObject
);
1804 if (quarantinedObject
.isObject()) {
1805 long id
= m_lastBoundObjectId
++;
1806 String objectId
= String::format("object#%ld", id
);
1807 m_idToWrappedObject
.set(objectId
, quarantinedObject
);
1808 ObjectGroupsMap::iterator it
= m_objectGroups
.find(objectGroup
);
1809 if (it
== m_objectGroups
.end())
1810 it
= m_objectGroups
.set(objectGroup
, Vector
<String
>()).first
;
1811 it
->second
.append(objectId
);
1812 function
.appendArgument(objectId
);
1814 ScriptValue wrapper
= function
.call();
1818 ScriptValue
InspectorController::unwrapObject(const String
& objectId
)
1820 HashMap
<String
, ScriptValue
>::iterator it
= m_idToWrappedObject
.find(objectId
);
1821 if (it
!= m_idToWrappedObject
.end())
1823 return ScriptValue();
1826 void InspectorController::releaseWrapperObjectGroup(const String
& objectGroup
)
1828 ObjectGroupsMap::iterator groupIt
= m_objectGroups
.find(objectGroup
);
1829 if (groupIt
== m_objectGroups
.end())
1832 Vector
<String
>& groupIds
= groupIt
->second
;
1833 for (Vector
<String
>::iterator it
= groupIds
.begin(); it
!= groupIds
.end(); ++it
)
1834 m_idToWrappedObject
.remove(*it
);
1835 m_objectGroups
.remove(groupIt
);
1838 void InspectorController::resetInjectedScript()
1840 ScriptFunctionCall
function(m_scriptState
, m_injectedScriptObj
, "reset");
1844 void InspectorController::deleteCookie(const String
& cookieName
, const String
& domain
)
1846 ResourcesMap::iterator resourcesEnd
= m_resources
.end();
1847 for (ResourcesMap::iterator it
= m_resources
.begin(); it
!= resourcesEnd
; ++it
) {
1848 Document
* document
= it
->second
->frame()->document();
1849 if (document
->url().host() == domain
)
1850 WebCore::deleteCookie(document
, document
->cookieURL(), cookieName
);
1854 } // namespace WebCore
1856 #endif // ENABLE(INSPECTOR)