Home | History | Annotate | Download | only in inspector
      1 /*
      2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Matt Lilek <webkit (at) 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 "InspectorController.h"
     32 
     33 #if ENABLE(INSPECTOR)
     34 
     35 #include "CString.h"
     36 #include "CachedResource.h"
     37 #include "Chrome.h"
     38 #include "Console.h"
     39 #include "ConsoleMessage.h"
     40 #include "Cookie.h"
     41 #include "CookieJar.h"
     42 #include "DOMWindow.h"
     43 #include "Document.h"
     44 #include "DocumentLoader.h"
     45 #include "Element.h"
     46 #include "FloatConversion.h"
     47 #include "FloatQuad.h"
     48 #include "FloatRect.h"
     49 #include "Frame.h"
     50 #include "FrameLoader.h"
     51 #include "FrameTree.h"
     52 #include "FrameView.h"
     53 #include "GraphicsContext.h"
     54 #include "HTMLFrameOwnerElement.h"
     55 #include "HitTestResult.h"
     56 #include "InjectedScript.h"
     57 #include "InjectedScriptHost.h"
     58 #include "InspectorBackend.h"
     59 #include "InspectorClient.h"
     60 #include "InspectorDOMAgent.h"
     61 #include "InspectorDOMStorageResource.h"
     62 #include "InspectorDatabaseResource.h"
     63 #include "InspectorFrontend.h"
     64 #include "InspectorFrontendHost.h"
     65 #include "InspectorResource.h"
     66 #include "InspectorTimelineAgent.h"
     67 #include "JavaScriptProfile.h"
     68 #include "Page.h"
     69 #include "ProgressTracker.h"
     70 #include "Range.h"
     71 #include "RenderInline.h"
     72 #include "ResourceRequest.h"
     73 #include "ResourceResponse.h"
     74 #include "ScriptCallStack.h"
     75 #include "ScriptDebugServer.h"
     76 #include "ScriptFunctionCall.h"
     77 #include "ScriptObject.h"
     78 #include "ScriptProfile.h"
     79 #include "ScriptProfiler.h"
     80 #include "ScriptString.h"
     81 #include "SecurityOrigin.h"
     82 #include "Settings.h"
     83 #include "SharedBuffer.h"
     84 #include "TextEncoding.h"
     85 #include "TextIterator.h"
     86 #include <wtf/CurrentTime.h>
     87 #include <wtf/ListHashSet.h>
     88 #include <wtf/RefCounted.h>
     89 #include <wtf/StdLibExtras.h>
     90 
     91 #if ENABLE(DATABASE)
     92 #include "Database.h"
     93 #endif
     94 
     95 #if ENABLE(DOM_STORAGE)
     96 #include "Storage.h"
     97 #include "StorageArea.h"
     98 #endif
     99 
    100 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    101 #include "JSJavaScriptCallFrame.h"
    102 #include "JavaScriptCallFrame.h"
    103 #include "JavaScriptDebugServer.h"
    104 
    105 #include <runtime/JSLock.h>
    106 #include <runtime/UString.h>
    107 
    108 using namespace JSC;
    109 #endif
    110 using namespace std;
    111 
    112 namespace WebCore {
    113 
    114 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
    115 static const char* const CPUProfileType = "CPU";
    116 static const char* const resourceTrackingEnabledSettingName = "resourceTrackingEnabled";
    117 static const char* const debuggerEnabledSettingName = "debuggerEnabled";
    118 static const char* const profilerEnabledSettingName = "profilerEnabled";
    119 static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight";
    120 static const char* const lastActivePanelSettingName = "lastActivePanel";
    121 const char* const InspectorController::FrontendSettingsSettingName = "frontendSettings";
    122 
    123 static const unsigned defaultAttachedHeight = 300;
    124 static const float minimumAttachedHeight = 250.0f;
    125 static const float maximumAttachedHeightRatio = 0.75f;
    126 static const unsigned maximumConsoleMessages = 1000;
    127 static const unsigned expireConsoleMessagesStep = 100;
    128 
    129 static unsigned s_inspectorControllerCount;
    130 
    131 InspectorController::InspectorController(Page* page, InspectorClient* client)
    132     : m_inspectedPage(page)
    133     , m_client(client)
    134     , m_page(0)
    135     , m_expiredConsoleMessageCount(0)
    136     , m_frontendScriptState(0)
    137     , m_windowVisible(false)
    138     , m_showAfterVisible(CurrentPanel)
    139     , m_groupLevel(0)
    140     , m_searchingForNode(false)
    141     , m_previousMessage(0)
    142     , m_resourceTrackingEnabled(false)
    143     , m_resourceTrackingSettingsLoaded(false)
    144     , m_inspectorBackend(InspectorBackend::create(this))
    145     , m_inspectorFrontendHost(InspectorFrontendHost::create(this, client))
    146     , m_injectedScriptHost(InjectedScriptHost::create(this))
    147 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    148     , m_debuggerEnabled(false)
    149     , m_attachDebuggerWhenShown(false)
    150 #endif
    151 #if ENABLE(JAVASCRIPT_DEBUGGER)
    152     , m_profilerEnabled(!WTF_USE_JSC)
    153     , m_recordingUserInitiatedProfile(false)
    154     , m_currentUserInitiatedProfileNumber(-1)
    155     , m_nextUserInitiatedProfileNumber(1)
    156     , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling)
    157 #endif
    158 {
    159     ASSERT_ARG(page, page);
    160     ASSERT_ARG(client, client);
    161     ++s_inspectorControllerCount;
    162 }
    163 
    164 InspectorController::~InspectorController()
    165 {
    166     // These should have been cleared in inspectedPageDestroyed().
    167     ASSERT(!m_client);
    168     ASSERT(!m_frontendScriptState);
    169     ASSERT(!m_inspectedPage);
    170     ASSERT(!m_page || (m_page && !m_page->parentInspectorController()));
    171 
    172     deleteAllValues(m_frameResources);
    173     deleteAllValues(m_consoleMessages);
    174 
    175     ASSERT(s_inspectorControllerCount);
    176     --s_inspectorControllerCount;
    177 
    178     releaseDOMAgent();
    179 
    180     m_inspectorBackend->disconnectController();
    181     m_inspectorFrontendHost->disconnectController();
    182     m_injectedScriptHost->disconnectController();
    183 }
    184 
    185 void InspectorController::inspectedPageDestroyed()
    186 {
    187     close();
    188 
    189     if (m_frontendScriptState) {
    190         ScriptGlobalObject::remove(m_frontendScriptState, "InspectorBackend");
    191         ScriptGlobalObject::remove(m_frontendScriptState, "InspectorFrontendHost");
    192     }
    193     ASSERT(m_inspectedPage);
    194     m_inspectedPage = 0;
    195 
    196     m_client->inspectorDestroyed();
    197     m_client = 0;
    198 }
    199 
    200 bool InspectorController::enabled() const
    201 {
    202     if (!m_inspectedPage)
    203         return false;
    204     return m_inspectedPage->settings()->developerExtrasEnabled();
    205 }
    206 
    207 String InspectorController::setting(const String& key) const
    208 {
    209     Settings::iterator it = m_settings.find(key);
    210     if (it != m_settings.end())
    211         return it->second;
    212 
    213     String value;
    214     m_client->populateSetting(key, &value);
    215     m_settings.set(key, value);
    216     return value;
    217 }
    218 
    219 void InspectorController::setSetting(const String& key, const String& value)
    220 {
    221     m_settings.set(key, value);
    222     m_client->storeSetting(key, value);
    223 }
    224 
    225 // Trying to inspect something in a frame with JavaScript disabled would later lead to
    226 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
    227 // for now prevent crashes here by never targeting a node in such a frame.
    228 static bool canPassNodeToJavaScript(Node* node)
    229 {
    230     if (!node)
    231         return false;
    232     Frame* frame = node->document()->frame();
    233     return frame && frame->script()->canExecuteScripts();
    234 }
    235 
    236 void InspectorController::inspect(Node* node)
    237 {
    238     if (!canPassNodeToJavaScript(node) || !enabled())
    239         return;
    240 
    241     show();
    242 
    243     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
    244         node = node->parentNode();
    245     m_nodeToFocus = node;
    246 
    247     if (!m_frontend) {
    248         m_showAfterVisible = ElementsPanel;
    249         return;
    250     }
    251 
    252     focusNode();
    253 }
    254 
    255 void InspectorController::focusNode()
    256 {
    257     if (!enabled())
    258         return;
    259 
    260     ASSERT(m_frontend);
    261     ASSERT(m_nodeToFocus);
    262 
    263     long id = m_domAgent->pushNodePathToFrontend(m_nodeToFocus.get());
    264     m_frontend->updateFocusedNode(id);
    265     m_nodeToFocus = 0;
    266 }
    267 
    268 void InspectorController::highlight(Node* node)
    269 {
    270     if (!enabled())
    271         return;
    272     ASSERT_ARG(node, node);
    273     m_highlightedNode = node;
    274     m_client->highlight(node);
    275 }
    276 
    277 void InspectorController::hideHighlight()
    278 {
    279     if (!enabled())
    280         return;
    281     m_highlightedNode = 0;
    282     m_client->hideHighlight();
    283 }
    284 
    285 bool InspectorController::windowVisible()
    286 {
    287     return m_windowVisible;
    288 }
    289 
    290 void InspectorController::setWindowVisible(bool visible, bool attached)
    291 {
    292     if (visible == m_windowVisible || !m_frontend)
    293         return;
    294 
    295     m_windowVisible = visible;
    296 
    297     if (m_windowVisible) {
    298         setAttachedWindow(attached);
    299         populateScriptObjects();
    300 
    301         if (m_showAfterVisible == CurrentPanel) {
    302           String lastActivePanelSetting = setting(lastActivePanelSettingName);
    303           m_showAfterVisible = specialPanelForJSName(lastActivePanelSetting);
    304         }
    305 
    306         if (m_nodeToFocus)
    307             focusNode();
    308 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    309         if (m_attachDebuggerWhenShown)
    310             enableDebugger();
    311 #endif
    312         showPanel(m_showAfterVisible);
    313     } else {
    314 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    315         // If the window is being closed with the debugger enabled,
    316         // remember this state to re-enable debugger on the next window
    317         // opening.
    318         bool debuggerWasEnabled = m_debuggerEnabled;
    319         disableDebugger();
    320         if (debuggerWasEnabled)
    321             m_attachDebuggerWhenShown = true;
    322 #endif
    323         if (m_searchingForNode)
    324             toggleSearchForNodeInPage();
    325         resetScriptObjects();
    326         stopTimelineProfiler();
    327     }
    328     m_showAfterVisible = CurrentPanel;
    329 }
    330 
    331 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, ScriptCallStack* callStack)
    332 {
    333     if (!enabled())
    334         return;
    335 
    336     addConsoleMessage(callStack->state(), new ConsoleMessage(source, type, level, callStack, m_groupLevel, type == TraceMessageType));
    337 }
    338 
    339 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
    340 {
    341     if (!enabled())
    342         return;
    343 
    344     addConsoleMessage(0, new ConsoleMessage(source, type, level, message, lineNumber, sourceID, m_groupLevel));
    345 }
    346 
    347 void InspectorController::addConsoleMessage(ScriptState* scriptState, ConsoleMessage* consoleMessage)
    348 {
    349     ASSERT(enabled());
    350     ASSERT_ARG(consoleMessage, consoleMessage);
    351 
    352     if (m_previousMessage && m_previousMessage->isEqual(scriptState, consoleMessage)) {
    353         m_previousMessage->incrementCount();
    354         delete consoleMessage;
    355         if (windowVisible())
    356             m_previousMessage->updateRepeatCountInConsole(m_frontend.get());
    357     } else {
    358         m_previousMessage = consoleMessage;
    359         m_consoleMessages.append(consoleMessage);
    360         if (windowVisible())
    361             m_previousMessage->addToConsole(m_frontend.get());
    362     }
    363 
    364     if (!windowVisible() && m_consoleMessages.size() >= maximumConsoleMessages) {
    365         m_expiredConsoleMessageCount += expireConsoleMessagesStep;
    366         for (size_t i = 0; i < expireConsoleMessagesStep; ++i)
    367             delete m_consoleMessages[i];
    368         m_consoleMessages.remove(0, expireConsoleMessagesStep);
    369     }
    370 }
    371 
    372 void InspectorController::clearConsoleMessages()
    373 {
    374     deleteAllValues(m_consoleMessages);
    375     m_consoleMessages.clear();
    376     m_expiredConsoleMessageCount = 0;
    377     m_previousMessage = 0;
    378     m_groupLevel = 0;
    379     m_injectedScriptHost->releaseWrapperObjectGroup(0 /* release the group in all scripts */, "console");
    380     if (m_domAgent)
    381         m_domAgent->releaseDanglingNodes();
    382     if (m_frontend)
    383         m_frontend->clearConsoleMessages();
    384 }
    385 
    386 void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack)
    387 {
    388     ++m_groupLevel;
    389 
    390     addConsoleMessage(callStack->state(), new ConsoleMessage(source, StartGroupMessageType, LogMessageLevel, callStack, m_groupLevel));
    391 }
    392 
    393 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
    394 {
    395     if (!m_groupLevel)
    396         return;
    397 
    398     --m_groupLevel;
    399 
    400     addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageType, LogMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
    401 }
    402 
    403 void InspectorController::markTimeline(const String& message)
    404 {
    405     if (timelineAgent())
    406         timelineAgent()->didMarkTimeline(message);
    407 }
    408 
    409 static unsigned constrainedAttachedWindowHeight(unsigned preferredHeight, unsigned totalWindowHeight)
    410 {
    411     return roundf(max(minimumAttachedHeight, min<float>(preferredHeight, totalWindowHeight * maximumAttachedHeightRatio)));
    412 }
    413 
    414 void InspectorController::attachWindow()
    415 {
    416     if (!enabled())
    417         return;
    418 
    419     unsigned inspectedPageHeight = m_inspectedPage->mainFrame()->view()->visibleHeight();
    420 
    421     m_client->attachWindow();
    422 
    423     String attachedHeight = setting(inspectorAttachedHeightName);
    424     bool success = true;
    425     int height = attachedHeight.toInt(&success);
    426     unsigned preferredHeight = success ? height : defaultAttachedHeight;
    427 
    428     // We need to constrain the window height here in case the user has resized the inspected page's window so that
    429     // the user's preferred height would be too big to display.
    430     m_client->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
    431 }
    432 
    433 void InspectorController::detachWindow()
    434 {
    435     if (!enabled())
    436         return;
    437     m_client->detachWindow();
    438 }
    439 
    440 void InspectorController::setAttachedWindow(bool attached)
    441 {
    442     if (!enabled() || !m_frontend)
    443         return;
    444 
    445     m_frontend->setAttachedWindow(attached);
    446 }
    447 
    448 void InspectorController::setAttachedWindowHeight(unsigned height)
    449 {
    450     if (!enabled())
    451         return;
    452 
    453     unsigned totalHeight = m_page->mainFrame()->view()->visibleHeight() + m_inspectedPage->mainFrame()->view()->visibleHeight();
    454     unsigned attachedHeight = constrainedAttachedWindowHeight(height, totalHeight);
    455 
    456     setSetting(inspectorAttachedHeightName, String::number(attachedHeight));
    457 
    458     m_client->setAttachedWindowHeight(attachedHeight);
    459 }
    460 
    461 void InspectorController::storeLastActivePanel(const String& panelName)
    462 {
    463     setSetting(lastActivePanelSettingName, panelName);
    464 }
    465 
    466 void InspectorController::toggleSearchForNodeInPage()
    467 {
    468     if (!enabled())
    469         return;
    470 
    471     m_searchingForNode = !m_searchingForNode;
    472     if (!m_searchingForNode)
    473         hideHighlight();
    474 }
    475 
    476 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
    477 {
    478     if (!enabled() || !m_searchingForNode)
    479         return;
    480 
    481     Node* node = result.innerNode();
    482     if (node)
    483         highlight(node);
    484 }
    485 
    486 void InspectorController::handleMousePressOnNode(Node* node)
    487 {
    488     if (!enabled())
    489         return;
    490 
    491     ASSERT(m_searchingForNode);
    492     ASSERT(node);
    493     if (!node)
    494         return;
    495 
    496     // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
    497     inspect(node);
    498 }
    499 
    500 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
    501 {
    502     if (!enabled() || !m_frontend || frame != m_inspectedPage->mainFrame())
    503         return;
    504     m_injectedScriptHost->discardInjectedScripts();
    505 }
    506 
    507 void InspectorController::windowScriptObjectAvailable()
    508 {
    509     if (!m_page || !enabled())
    510         return;
    511 
    512     // Grant the inspector the ability to script the inspected page.
    513     m_page->mainFrame()->document()->securityOrigin()->grantUniversalAccess();
    514     m_frontendScriptState = scriptStateFromPage(debuggerWorld(), m_page);
    515     ScriptGlobalObject::set(m_frontendScriptState, "InspectorBackend", m_inspectorBackend.get());
    516     ScriptGlobalObject::set(m_frontendScriptState, "InspectorFrontendHost", m_inspectorFrontendHost.get());
    517 }
    518 
    519 void InspectorController::scriptObjectReady()
    520 {
    521     ASSERT(m_frontendScriptState);
    522     if (!m_frontendScriptState)
    523         return;
    524 
    525     ScriptObject webInspectorObj;
    526     if (!ScriptGlobalObject::get(m_frontendScriptState, "WebInspector", webInspectorObj))
    527         return;
    528     setFrontendProxyObject(m_frontendScriptState, webInspectorObj);
    529 
    530 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    531     String debuggerEnabled = setting(debuggerEnabledSettingName);
    532     if (debuggerEnabled == "true")
    533         enableDebugger();
    534     String profilerEnabled = setting(profilerEnabledSettingName);
    535     if (profilerEnabled == "true")
    536         enableProfiler();
    537 #endif
    538 
    539     // Make sure our window is visible now that the page loaded
    540     showWindow();
    541 
    542     m_client->inspectorWindowObjectCleared();
    543 }
    544 
    545 void InspectorController::setFrontendProxyObject(ScriptState* scriptState, ScriptObject webInspectorObj, ScriptObject)
    546 {
    547     m_frontendScriptState = scriptState;
    548     m_frontend.set(new InspectorFrontend(this, webInspectorObj));
    549     releaseDOMAgent();
    550     m_domAgent = InspectorDOMAgent::create(m_frontend.get());
    551     if (m_timelineAgent)
    552         m_timelineAgent->resetFrontendProxyObject(m_frontend.get());
    553 }
    554 
    555 void InspectorController::show()
    556 {
    557     if (!enabled())
    558         return;
    559 
    560     if (!m_page) {
    561         if (m_frontend)
    562             return; // We are using custom frontend - no need to create page.
    563 
    564         m_page = m_client->createPage();
    565         if (!m_page)
    566             return;
    567         m_page->setParentInspectorController(this);
    568 
    569         // showWindow() will be called after the page loads in scriptObjectReady()
    570         return;
    571     }
    572 
    573     showWindow();
    574 }
    575 
    576 void InspectorController::showPanel(SpecialPanels panel)
    577 {
    578     if (!enabled())
    579         return;
    580 
    581     show();
    582 
    583     if (!m_frontend) {
    584         m_showAfterVisible = panel;
    585         return;
    586     }
    587 
    588     if (panel == CurrentPanel)
    589         return;
    590 
    591     m_frontend->showPanel(panel);
    592 }
    593 
    594 void InspectorController::close()
    595 {
    596     if (!enabled())
    597         return;
    598 
    599 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    600     stopUserInitiatedProfiling();
    601     disableDebugger();
    602 #endif
    603     closeWindow();
    604 
    605     releaseDOMAgent();
    606     m_frontend.set(0);
    607     m_timelineAgent = 0;
    608     m_frontendScriptState = 0;
    609     if (m_page) {
    610         if (!m_page->mainFrame() || !m_page->mainFrame()->loader() || !m_page->mainFrame()->loader()->isLoading()) {
    611             m_page->setParentInspectorController(0);
    612             m_page = 0;
    613         }
    614     }
    615 }
    616 
    617 void InspectorController::showWindow()
    618 {
    619     ASSERT(enabled());
    620 
    621     unsigned inspectedPageHeight = m_inspectedPage->mainFrame()->view()->visibleHeight();
    622 
    623     m_client->showWindow();
    624 
    625     String attachedHeight = setting(inspectorAttachedHeightName);
    626     bool success = true;
    627     int height = attachedHeight.toInt(&success);
    628     unsigned preferredHeight = success ? height : defaultAttachedHeight;
    629 
    630     // This call might not go through (if the window starts out detached), but if the window is initially created attached,
    631     // InspectorController::attachWindow is never called, so we need to make sure to set the attachedWindowHeight.
    632     // FIXME: Clean up code so we only have to call setAttachedWindowHeight in InspectorController::attachWindow
    633     m_client->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
    634 }
    635 
    636 void InspectorController::closeWindow()
    637 {
    638     m_client->closeWindow();
    639 }
    640 
    641 void InspectorController::releaseDOMAgent()
    642 {
    643     // m_domAgent is RefPtr. Remove DOM listeners first to ensure that there are
    644     // no references to the DOM agent from the DOM tree.
    645     if (m_domAgent)
    646         m_domAgent->reset();
    647     m_domAgent = 0;
    648 }
    649 
    650 void InspectorController::populateScriptObjects()
    651 {
    652     ASSERT(m_frontend);
    653     if (!m_frontend)
    654         return;
    655 
    656     m_frontend->populateFrontendSettings(setting(FrontendSettingsSettingName));
    657     m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
    658 
    659     ResourcesMap::iterator resourcesEnd = m_resources.end();
    660     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
    661         it->second->updateScriptObject(m_frontend.get());
    662 
    663     if (m_expiredConsoleMessageCount)
    664         m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount);
    665     unsigned messageCount = m_consoleMessages.size();
    666     for (unsigned i = 0; i < messageCount; ++i)
    667         m_consoleMessages[i]->addToConsole(m_frontend.get());
    668 
    669 #if ENABLE(DATABASE)
    670     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
    671     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
    672         it->second->bind(m_frontend.get());
    673 #endif
    674 #if ENABLE(DOM_STORAGE)
    675     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
    676     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
    677         it->second->bind(m_frontend.get());
    678 #endif
    679 
    680     m_frontend->populateInterface();
    681 
    682     // Dispatch pending frontend commands
    683     for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
    684         m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
    685     m_pendingEvaluateTestCommands.clear();
    686 }
    687 
    688 void InspectorController::resetScriptObjects()
    689 {
    690     if (!m_frontend)
    691         return;
    692 
    693     ResourcesMap::iterator resourcesEnd = m_resources.end();
    694     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
    695         it->second->releaseScriptObject(m_frontend.get(), false);
    696 
    697 #if ENABLE(DATABASE)
    698     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
    699     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
    700         it->second->unbind();
    701 #endif
    702 #if ENABLE(DOM_STORAGE)
    703     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
    704     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
    705         it->second->unbind();
    706 #endif
    707 
    708     if (m_timelineAgent)
    709         m_timelineAgent->reset();
    710 
    711     m_frontend->reset();
    712     m_domAgent->reset();
    713 }
    714 
    715 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
    716 {
    717     ASSERT_ARG(resourceMap, resourceMap);
    718 
    719     ResourcesMap mapCopy(*resourceMap);
    720     ResourcesMap::iterator end = mapCopy.end();
    721     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
    722         InspectorResource* resource = (*it).second.get();
    723         if (resource == m_mainResource)
    724             continue;
    725 
    726         if (!loaderToKeep || !resource->isSameLoader(loaderToKeep)) {
    727             removeResource(resource);
    728             if (windowVisible())
    729                 resource->releaseScriptObject(m_frontend.get(), true);
    730         }
    731     }
    732 }
    733 
    734 void InspectorController::didCommitLoad(DocumentLoader* loader)
    735 {
    736     if (!enabled())
    737         return;
    738 
    739     ASSERT(m_inspectedPage);
    740 
    741     if (loader->frame() == m_inspectedPage->mainFrame()) {
    742         m_client->inspectedURLChanged(loader->url().string());
    743 
    744         m_injectedScriptHost->discardInjectedScripts();
    745         clearConsoleMessages();
    746 
    747         m_times.clear();
    748         m_counts.clear();
    749 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
    750         m_profiles.clear();
    751         m_currentUserInitiatedProfileNumber = 1;
    752         m_nextUserInitiatedProfileNumber = 1;
    753 #endif
    754         // resetScriptObjects should be called before database and DOM storage
    755         // resources are cleared so that it has a chance to unbind them.
    756         resetScriptObjects();
    757 
    758 #if ENABLE(DATABASE)
    759         m_databaseResources.clear();
    760 #endif
    761 #if ENABLE(DOM_STORAGE)
    762         m_domStorageResources.clear();
    763 #endif
    764 
    765         if (m_frontend) {
    766             if (!loader->frameLoader()->isLoadingFromCachedPage()) {
    767                 ASSERT(m_mainResource && m_mainResource->isSameLoader(loader));
    768                 // We don't add the main resource until its load is committed. This is
    769                 // needed to keep the load for a user-entered URL from showing up in the
    770                 // list of resources for the page they are navigating away from.
    771                 if (windowVisible())
    772                     m_mainResource->updateScriptObject(m_frontend.get());
    773             } else {
    774                 // Pages loaded from the page cache are committed before
    775                 // m_mainResource is the right resource for this load, so we
    776                 // clear it here. It will be re-assigned in
    777                 // identifierForInitialRequest.
    778                 m_mainResource = 0;
    779             }
    780             if (windowVisible()) {
    781                 m_frontend->didCommitLoad();
    782                 m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
    783             }
    784         }
    785     }
    786 
    787     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
    788         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
    789             pruneResources(resourceMap, loader);
    790 }
    791 
    792 void InspectorController::frameDetachedFromParent(Frame* frame)
    793 {
    794     if (!enabled())
    795         return;
    796     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
    797         removeAllResources(resourceMap);
    798 }
    799 
    800 void InspectorController::addResource(InspectorResource* resource)
    801 {
    802     m_resources.set(resource->identifier(), resource);
    803     m_knownResources.add(resource->requestURL());
    804 
    805     Frame* frame = resource->frame();
    806     ResourcesMap* resourceMap = m_frameResources.get(frame);
    807     if (resourceMap)
    808         resourceMap->set(resource->identifier(), resource);
    809     else {
    810         resourceMap = new ResourcesMap;
    811         resourceMap->set(resource->identifier(), resource);
    812         m_frameResources.set(frame, resourceMap);
    813     }
    814 }
    815 
    816 void InspectorController::removeResource(InspectorResource* resource)
    817 {
    818     m_resources.remove(resource->identifier());
    819     String requestURL = resource->requestURL();
    820     if (!requestURL.isNull())
    821         m_knownResources.remove(requestURL);
    822 
    823     Frame* frame = resource->frame();
    824     ResourcesMap* resourceMap = m_frameResources.get(frame);
    825     if (!resourceMap) {
    826         ASSERT_NOT_REACHED();
    827         return;
    828     }
    829 
    830     resourceMap->remove(resource->identifier());
    831     if (resourceMap->isEmpty()) {
    832         m_frameResources.remove(frame);
    833         delete resourceMap;
    834     }
    835 }
    836 
    837 InspectorResource* InspectorController::getTrackedResource(unsigned long identifier)
    838 {
    839     if (!enabled())
    840         return 0;
    841 
    842     if (m_resourceTrackingEnabled)
    843         return m_resources.get(identifier).get();
    844 
    845     bool isMainResource = m_mainResource && m_mainResource->identifier() == identifier;
    846     if (isMainResource)
    847         return m_mainResource.get();
    848 
    849     return 0;
    850 }
    851 
    852 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource)
    853 {
    854     if (!enabled())
    855         return;
    856 
    857     // If the resource URL is already known, we don't need to add it again since this is just a cached load.
    858     if (m_knownResources.contains(cachedResource->url()))
    859         return;
    860 
    861     ASSERT(m_inspectedPage);
    862     bool isMainResource = isMainResourceLoader(loader, KURL(ParsedURLString, cachedResource->url()));
    863     ensureResourceTrackingSettingsLoaded();
    864     if (!isMainResource && !m_resourceTrackingEnabled)
    865         return;
    866 
    867     RefPtr<InspectorResource> resource = InspectorResource::createCached(m_inspectedPage->progress()->createUniqueIdentifier(), loader, cachedResource);
    868 
    869     if (isMainResource) {
    870         m_mainResource = resource;
    871         resource->markMainResource();
    872     }
    873 
    874     addResource(resource.get());
    875 
    876     if (windowVisible())
    877         resource->updateScriptObject(m_frontend.get());
    878 }
    879 
    880 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
    881 {
    882     if (!enabled())
    883         return;
    884     ASSERT(m_inspectedPage);
    885 
    886     bool isMainResource = isMainResourceLoader(loader, request.url());
    887     ensureResourceTrackingSettingsLoaded();
    888     if (!isMainResource && !m_resourceTrackingEnabled)
    889         return;
    890 
    891     RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, request.url());
    892 
    893     if (isMainResource) {
    894         m_mainResource = resource;
    895         resource->markMainResource();
    896     }
    897 
    898     addResource(resource.get());
    899 
    900     if (windowVisible() && loader->frameLoader()->isLoadingFromCachedPage() && resource == m_mainResource)
    901         resource->updateScriptObject(m_frontend.get());
    902 }
    903 
    904 void InspectorController::mainResourceFiredDOMContentEvent(DocumentLoader* loader, const KURL& url)
    905 {
    906     if (!enabled() || !isMainResourceLoader(loader, url))
    907         return;
    908 
    909     if (m_mainResource) {
    910         m_mainResource->markDOMContentEventTime();
    911         if (windowVisible())
    912             m_mainResource->updateScriptObject(m_frontend.get());
    913     }
    914 }
    915 
    916 void InspectorController::mainResourceFiredLoadEvent(DocumentLoader* loader, const KURL& url)
    917 {
    918     if (!enabled() || !isMainResourceLoader(loader, url))
    919         return;
    920 
    921     if (m_mainResource) {
    922         m_mainResource->markLoadEventTime();
    923         if (windowVisible())
    924             m_mainResource->updateScriptObject(m_frontend.get());
    925     }
    926 }
    927 
    928 bool InspectorController::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
    929 {
    930     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
    931 }
    932 
    933 void InspectorController::willSendRequest(unsigned long identifier, const ResourceRequest& request, const ResourceResponse& redirectResponse)
    934 {
    935     bool isMainResource = (m_mainResource && m_mainResource->identifier() == identifier);
    936     if (m_timelineAgent)
    937         m_timelineAgent->willSendResourceRequest(identifier, isMainResource, request);
    938 
    939     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
    940     if (!resource)
    941         return;
    942 
    943     if (!redirectResponse.isNull()) {
    944         resource->markResponseReceivedTime();
    945         resource->endTiming();
    946         resource->updateResponse(redirectResponse);
    947 
    948         // We always store last redirect by the original id key. Rest of the redirects are stored within the last one.
    949         unsigned long id = m_inspectedPage->progress()->createUniqueIdentifier();
    950         RefPtr<InspectorResource> withRedirect = resource->appendRedirect(id, request.url());
    951         removeResource(resource.get());
    952         addResource(withRedirect.get());
    953         if (isMainResource) {
    954             m_mainResource = withRedirect;
    955             withRedirect->markMainResource();
    956         }
    957         resource = withRedirect;
    958     }
    959 
    960     resource->startTiming();
    961     resource->updateRequest(request);
    962 
    963     if (resource != m_mainResource && windowVisible())
    964         resource->updateScriptObject(m_frontend.get());
    965 }
    966 
    967 void InspectorController::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
    968 {
    969     if (m_timelineAgent)
    970         m_timelineAgent->didReceiveResourceResponse(identifier, response);
    971 
    972     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
    973     if (!resource)
    974         return;
    975 
    976     resource->updateResponse(response);
    977     resource->markResponseReceivedTime();
    978 
    979     if (resource != m_mainResource && windowVisible())
    980         resource->updateScriptObject(m_frontend.get());
    981 }
    982 
    983 void InspectorController::didReceiveContentLength(unsigned long identifier, int lengthReceived)
    984 {
    985     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
    986     if (!resource)
    987         return;
    988 
    989     resource->addLength(lengthReceived);
    990 
    991     if (resource != m_mainResource && windowVisible())
    992         resource->updateScriptObject(m_frontend.get());
    993 }
    994 
    995 void InspectorController::didFinishLoading(unsigned long identifier)
    996 {
    997     if (m_timelineAgent)
    998         m_timelineAgent->didFinishLoadingResource(identifier, false);
    999 
   1000     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
   1001     if (!resource)
   1002         return;
   1003 
   1004     resource->endTiming();
   1005 
   1006     if (resource != m_mainResource && windowVisible())
   1007         resource->updateScriptObject(m_frontend.get());
   1008 }
   1009 
   1010 void InspectorController::didFailLoading(unsigned long identifier, const ResourceError& /*error*/)
   1011 {
   1012     if (m_timelineAgent)
   1013         m_timelineAgent->didFinishLoadingResource(identifier, true);
   1014 
   1015     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
   1016     if (!resource)
   1017         return;
   1018 
   1019     resource->markFailed();
   1020     resource->endTiming();
   1021 
   1022     if (resource != m_mainResource && windowVisible())
   1023         resource->updateScriptObject(m_frontend.get());
   1024 }
   1025 
   1026 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString)
   1027 {
   1028     if (!enabled() || !m_resourceTrackingEnabled)
   1029         return;
   1030 
   1031     InspectorResource* resource = m_resources.get(identifier).get();
   1032     if (!resource)
   1033         return;
   1034 
   1035     resource->setXMLHttpResponseText(sourceString);
   1036 
   1037     if (windowVisible())
   1038         resource->updateScriptObject(m_frontend.get());
   1039 }
   1040 
   1041 void InspectorController::scriptImported(unsigned long identifier, const String& sourceString)
   1042 {
   1043     if (!enabled() || !m_resourceTrackingEnabled)
   1044         return;
   1045 
   1046     InspectorResource* resource = m_resources.get(identifier).get();
   1047     if (!resource)
   1048         return;
   1049 
   1050     // FIXME: imported script and XHR response are currently viewed as the same
   1051     // thing by the Inspector. They should be made into distinct types.
   1052     resource->setXMLHttpResponseText(ScriptString(sourceString));
   1053 
   1054     if (windowVisible())
   1055         resource->updateScriptObject(m_frontend.get());
   1056 }
   1057 
   1058 void InspectorController::enableResourceTracking(bool always, bool reload)
   1059 {
   1060     if (!enabled())
   1061         return;
   1062 
   1063     if (always)
   1064         setSetting(resourceTrackingEnabledSettingName, "true");
   1065 
   1066     if (m_resourceTrackingEnabled)
   1067         return;
   1068 
   1069     ASSERT(m_inspectedPage);
   1070     m_resourceTrackingEnabled = true;
   1071     if (m_frontend)
   1072         m_frontend->resourceTrackingWasEnabled();
   1073 
   1074     if (reload)
   1075         m_inspectedPage->mainFrame()->loader()->reload();
   1076 }
   1077 
   1078 void InspectorController::disableResourceTracking(bool always)
   1079 {
   1080     if (!enabled())
   1081         return;
   1082 
   1083     if (always)
   1084         setSetting(resourceTrackingEnabledSettingName, "false");
   1085 
   1086     ASSERT(m_inspectedPage);
   1087     m_resourceTrackingEnabled = false;
   1088     if (m_frontend)
   1089         m_frontend->resourceTrackingWasDisabled();
   1090 }
   1091 
   1092 void InspectorController::ensureResourceTrackingSettingsLoaded()
   1093 {
   1094     if (m_resourceTrackingSettingsLoaded)
   1095         return;
   1096     m_resourceTrackingSettingsLoaded = true;
   1097 
   1098     String resourceTracking = setting(resourceTrackingEnabledSettingName);
   1099     if (resourceTracking == "true")
   1100         m_resourceTrackingEnabled = true;
   1101 }
   1102 
   1103 void InspectorController::startTimelineProfiler()
   1104 {
   1105     if (!enabled())
   1106         return;
   1107 
   1108     if (m_timelineAgent)
   1109         return;
   1110 
   1111     m_timelineAgent = new InspectorTimelineAgent(m_frontend.get());
   1112     if (m_frontend)
   1113         m_frontend->timelineProfilerWasStarted();
   1114 }
   1115 
   1116 void InspectorController::stopTimelineProfiler()
   1117 {
   1118     if (!enabled())
   1119         return;
   1120 
   1121     if (!m_timelineAgent)
   1122         return;
   1123 
   1124     m_timelineAgent = 0;
   1125     if (m_frontend)
   1126         m_frontend->timelineProfilerWasStopped();
   1127 }
   1128 
   1129 #if ENABLE(DATABASE)
   1130 void InspectorController::selectDatabase(Database* database)
   1131 {
   1132     if (!m_frontend)
   1133         return;
   1134 
   1135     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != m_databaseResources.end(); ++it) {
   1136         if (it->second->database() == database) {
   1137             m_frontend->selectDatabase(it->first);
   1138             break;
   1139         }
   1140     }
   1141 }
   1142 
   1143 Database* InspectorController::databaseForId(int databaseId)
   1144 {
   1145     DatabaseResourcesMap::iterator it = m_databaseResources.find(databaseId);
   1146     if (it == m_databaseResources.end())
   1147         return 0;
   1148     return it->second->database();
   1149 }
   1150 
   1151 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
   1152 {
   1153     if (!enabled())
   1154         return;
   1155 
   1156     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
   1157 
   1158     m_databaseResources.set(resource->id(), resource);
   1159 
   1160     // Resources are only bound while visible.
   1161     if (windowVisible())
   1162         resource->bind(m_frontend.get());
   1163 }
   1164 #endif
   1165 
   1166 void InspectorController::getCookies(long callId)
   1167 {
   1168     if (!m_frontend)
   1169         return;
   1170 
   1171     // If we can get raw cookies.
   1172     ListHashSet<Cookie> rawCookiesList;
   1173 
   1174     // If we can't get raw cookies - fall back to String representation
   1175     String stringCookiesList;
   1176 
   1177     // Return value to getRawCookies should be the same for every call because
   1178     // the return value is platform/network backend specific, and the call will
   1179     // always return the same true/false value.
   1180     bool rawCookiesImplemented = false;
   1181 
   1182     ResourcesMap::iterator resourcesEnd = m_resources.end();
   1183     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
   1184         Document* document = it->second->frame()->document();
   1185         Vector<Cookie> docCookiesList;
   1186         rawCookiesImplemented = getRawCookies(document, it->second->requestURL(), docCookiesList);
   1187 
   1188         if (!rawCookiesImplemented) {
   1189             // FIXME: We need duplication checking for the String representation of cookies.
   1190             ExceptionCode ec = 0;
   1191             stringCookiesList += document->cookie(ec);
   1192             // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
   1193             // because "document" is the document of the main frame of the page.
   1194             ASSERT(!ec);
   1195         } else {
   1196             int cookiesSize = docCookiesList.size();
   1197             for (int i = 0; i < cookiesSize; i++) {
   1198                 if (!rawCookiesList.contains(docCookiesList[i]))
   1199                     rawCookiesList.add(docCookiesList[i]);
   1200             }
   1201         }
   1202     }
   1203 
   1204     if (!rawCookiesImplemented)
   1205         m_frontend->didGetCookies(callId, m_frontend->newScriptArray(), stringCookiesList);
   1206     else
   1207         m_frontend->didGetCookies(callId, buildArrayForCookies(rawCookiesList), String());
   1208 }
   1209 
   1210 ScriptArray InspectorController::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
   1211 {
   1212     ScriptArray cookies = m_frontend->newScriptArray();
   1213 
   1214     ListHashSet<Cookie>::iterator end = cookiesList.end();
   1215     ListHashSet<Cookie>::iterator it = cookiesList.begin();
   1216     for (int i = 0; it != end; ++it, i++)
   1217         cookies.set(i, buildObjectForCookie(*it));
   1218 
   1219     return cookies;
   1220 }
   1221 
   1222 ScriptObject InspectorController::buildObjectForCookie(const Cookie& cookie)
   1223 {
   1224     ScriptObject value = m_frontend->newScriptObject();
   1225     value.set("name", cookie.name);
   1226     value.set("value", cookie.value);
   1227     value.set("domain", cookie.domain);
   1228     value.set("path", cookie.path);
   1229     value.set("expires", cookie.expires);
   1230     value.set("size", (cookie.name.length() + cookie.value.length()));
   1231     value.set("httpOnly", cookie.httpOnly);
   1232     value.set("secure", cookie.secure);
   1233     value.set("session", cookie.session);
   1234     return value;
   1235 }
   1236 
   1237 #if ENABLE(DOM_STORAGE)
   1238 void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame)
   1239 {
   1240     if (!enabled())
   1241         return;
   1242 
   1243     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
   1244     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
   1245         if (it->second->isSameHostAndType(frame, isLocalStorage))
   1246             return;
   1247 
   1248     RefPtr<Storage> domStorage = Storage::create(frame, storageArea);
   1249     RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame);
   1250 
   1251     m_domStorageResources.set(resource->id(), resource);
   1252 
   1253     // Resources are only bound while visible.
   1254     if (windowVisible())
   1255         resource->bind(m_frontend.get());
   1256 }
   1257 
   1258 void InspectorController::selectDOMStorage(Storage* storage)
   1259 {
   1260     ASSERT(storage);
   1261     if (!m_frontend)
   1262         return;
   1263 
   1264     Frame* frame = storage->frame();
   1265     bool isLocalStorage = (frame->domWindow()->localStorage() == storage);
   1266     int storageResourceId = 0;
   1267     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
   1268     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) {
   1269         if (it->second->isSameHostAndType(frame, isLocalStorage)) {
   1270             storageResourceId = it->first;
   1271             break;
   1272         }
   1273     }
   1274     if (storageResourceId)
   1275         m_frontend->selectDOMStorage(storageResourceId);
   1276 }
   1277 
   1278 void InspectorController::getDOMStorageEntries(int callId, int storageId)
   1279 {
   1280     if (!m_frontend)
   1281         return;
   1282 
   1283     ScriptArray jsonArray = m_frontend->newScriptArray();
   1284     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
   1285     if (storageResource) {
   1286         storageResource->startReportingChangesToFrontend();
   1287         Storage* domStorage = storageResource->domStorage();
   1288         for (unsigned i = 0; i < domStorage->length(); ++i) {
   1289             String name(domStorage->key(i));
   1290             String value(domStorage->getItem(name));
   1291             ScriptArray entry = m_frontend->newScriptArray();
   1292             entry.set(0, name);
   1293             entry.set(1, value);
   1294             jsonArray.set(i, entry);
   1295         }
   1296     }
   1297     m_frontend->didGetDOMStorageEntries(callId, jsonArray);
   1298 }
   1299 
   1300 void InspectorController::setDOMStorageItem(long callId, long storageId, const String& key, const String& value)
   1301 {
   1302     if (!m_frontend)
   1303         return;
   1304 
   1305     bool success = false;
   1306     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
   1307     if (storageResource) {
   1308         ExceptionCode exception = 0;
   1309         storageResource->domStorage()->setItem(key, value, exception);
   1310         success = !exception;
   1311     }
   1312     m_frontend->didSetDOMStorageItem(callId, success);
   1313 }
   1314 
   1315 void InspectorController::removeDOMStorageItem(long callId, long storageId, const String& key)
   1316 {
   1317     if (!m_frontend)
   1318         return;
   1319 
   1320     bool success = false;
   1321     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
   1322     if (storageResource) {
   1323         storageResource->domStorage()->removeItem(key);
   1324         success = true;
   1325     }
   1326     m_frontend->didRemoveDOMStorageItem(callId, success);
   1327 }
   1328 
   1329 InspectorDOMStorageResource* InspectorController::getDOMStorageResourceForId(int storageId)
   1330 {
   1331     DOMStorageResourcesMap::iterator it = m_domStorageResources.find(storageId);
   1332     if (it == m_domStorageResources.end())
   1333         return 0;
   1334     return it->second.get();
   1335 }
   1336 #endif
   1337 
   1338 void InspectorController::moveWindowBy(float x, float y) const
   1339 {
   1340     if (!m_page || !enabled())
   1341         return;
   1342 
   1343     FloatRect frameRect = m_page->chrome()->windowRect();
   1344     frameRect.move(x, y);
   1345     m_page->chrome()->setWindowRect(frameRect);
   1346 }
   1347 
   1348 #if ENABLE(JAVASCRIPT_DEBUGGER)
   1349 void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
   1350 {
   1351     if (!enabled())
   1352         return;
   1353 
   1354     RefPtr<ScriptProfile> profile = prpProfile;
   1355     m_profiles.add(profile->uid(), profile);
   1356 
   1357     if (m_frontend) {
   1358 #if USE(JSC)
   1359         JSLock lock(SilenceAssertionsOnly);
   1360 #endif
   1361         m_frontend->addProfileHeader(createProfileHeader(*profile));
   1362     }
   1363 
   1364     addProfileFinishedMessageToConsole(profile, lineNumber, sourceURL);
   1365 }
   1366 
   1367 void InspectorController::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
   1368 {
   1369     RefPtr<ScriptProfile> profile = prpProfile;
   1370 
   1371     String message = String::format("Profile \"webkit-profile://%s/%s#%d\" finished.", CPUProfileType, encodeWithURLEscapeSequences(profile->title()).utf8().data(), profile->uid());
   1372     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
   1373 }
   1374 
   1375 void InspectorController::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
   1376 {
   1377     String message = String::format("Profile \"webkit-profile://%s/%s#0\" started.", CPUProfileType, encodeWithURLEscapeSequences(title).utf8().data());
   1378     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
   1379 }
   1380 
   1381 void InspectorController::getProfileHeaders(long callId)
   1382 {
   1383     if (!m_frontend)
   1384         return;
   1385     ScriptArray result = m_frontend->newScriptArray();
   1386     ProfilesMap::iterator profilesEnd = m_profiles.end();
   1387     int i = 0;
   1388     for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
   1389         result.set(i++, createProfileHeader(*it->second));
   1390     m_frontend->didGetProfileHeaders(callId, result);
   1391 }
   1392 
   1393 void InspectorController::getProfile(long callId, unsigned uid)
   1394 {
   1395     if (!m_frontend)
   1396         return;
   1397     ProfilesMap::iterator it = m_profiles.find(uid);
   1398 #if USE(JSC)
   1399     if (it != m_profiles.end())
   1400         m_frontend->didGetProfile(callId, toJS(m_frontendScriptState, it->second.get()));
   1401 #endif
   1402 }
   1403 
   1404 ScriptObject InspectorController::createProfileHeader(const ScriptProfile& profile)
   1405 {
   1406     ScriptObject header = m_frontend->newScriptObject();
   1407     header.set("title", profile.title());
   1408     header.set("uid", profile.uid());
   1409     header.set("typeId", String(CPUProfileType));
   1410     return header;
   1411 }
   1412 
   1413 String InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false)
   1414 {
   1415     if (incrementProfileNumber)
   1416         m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
   1417 
   1418     return String::format("%s.%d", UserInitiatedProfileName, m_currentUserInitiatedProfileNumber);
   1419 }
   1420 
   1421 void InspectorController::startUserInitiatedProfilingSoon()
   1422 {
   1423     m_startProfiling.startOneShot(0);
   1424 }
   1425 
   1426 void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*)
   1427 {
   1428     if (!enabled())
   1429         return;
   1430 
   1431     if (!profilerEnabled()) {
   1432         enableProfiler(false, true);
   1433         ScriptDebugServer::recompileAllJSFunctions();
   1434     }
   1435 
   1436     m_recordingUserInitiatedProfile = true;
   1437 
   1438     String title = getCurrentUserInitiatedProfileName(true);
   1439 
   1440 #if USE(JSC)
   1441     ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
   1442 #else
   1443     ScriptState* scriptState = 0;
   1444 #endif
   1445     ScriptProfiler::start(scriptState, title);
   1446 
   1447     addStartProfilingMessageToConsole(title, 0, String());
   1448 
   1449     toggleRecordButton(true);
   1450 }
   1451 
   1452 void InspectorController::stopUserInitiatedProfiling()
   1453 {
   1454     if (!enabled())
   1455         return;
   1456 
   1457     m_recordingUserInitiatedProfile = false;
   1458 
   1459     String title = getCurrentUserInitiatedProfileName();
   1460 
   1461 #if USE(JSC)
   1462     ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
   1463 #else
   1464     ScriptState* scriptState = 0;
   1465 #endif
   1466     RefPtr<ScriptProfile> profile = ScriptProfiler::stop(scriptState, title);
   1467     if (profile)
   1468         addProfile(profile, 0, String());
   1469 
   1470     toggleRecordButton(false);
   1471 }
   1472 
   1473 void InspectorController::toggleRecordButton(bool isProfiling)
   1474 {
   1475     if (!m_frontend)
   1476         return;
   1477     m_frontend->setRecordingProfile(isProfiling);
   1478 }
   1479 
   1480 void InspectorController::enableProfiler(bool always, bool skipRecompile)
   1481 {
   1482     if (always)
   1483         setSetting(profilerEnabledSettingName, "true");
   1484 
   1485     if (m_profilerEnabled)
   1486         return;
   1487 
   1488     m_profilerEnabled = true;
   1489 
   1490     if (!skipRecompile)
   1491         ScriptDebugServer::recompileAllJSFunctionsSoon();
   1492 
   1493     if (m_frontend)
   1494         m_frontend->profilerWasEnabled();
   1495 }
   1496 
   1497 void InspectorController::disableProfiler(bool always)
   1498 {
   1499     if (always)
   1500         setSetting(profilerEnabledSettingName, "false");
   1501 
   1502     if (!m_profilerEnabled)
   1503         return;
   1504 
   1505     m_profilerEnabled = false;
   1506 
   1507     ScriptDebugServer::recompileAllJSFunctionsSoon();
   1508 
   1509     if (m_frontend)
   1510         m_frontend->profilerWasDisabled();
   1511 }
   1512 #endif
   1513 
   1514 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
   1515 void InspectorController::enableDebuggerFromFrontend(bool always)
   1516 {
   1517     if (always)
   1518         setSetting(debuggerEnabledSettingName, "true");
   1519 
   1520     ASSERT(m_inspectedPage);
   1521 
   1522     JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
   1523     JavaScriptDebugServer::shared().clearBreakpoints();
   1524 
   1525     m_debuggerEnabled = true;
   1526     m_frontend->debuggerWasEnabled();
   1527 }
   1528 
   1529 void InspectorController::enableDebugger()
   1530 {
   1531     if (!enabled())
   1532         return;
   1533 
   1534     if (m_debuggerEnabled)
   1535         return;
   1536 
   1537     if (!m_frontendScriptState || !m_frontend)
   1538         m_attachDebuggerWhenShown = true;
   1539     else {
   1540         m_frontend->attachDebuggerWhenShown();
   1541         m_attachDebuggerWhenShown = false;
   1542     }
   1543 }
   1544 
   1545 void InspectorController::disableDebugger(bool always)
   1546 {
   1547     if (!enabled())
   1548         return;
   1549 
   1550     if (always)
   1551         setSetting(debuggerEnabledSettingName, "false");
   1552 
   1553     ASSERT(m_inspectedPage);
   1554 
   1555     JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
   1556 
   1557     m_debuggerEnabled = false;
   1558     m_attachDebuggerWhenShown = false;
   1559 
   1560     if (m_frontend)
   1561         m_frontend->debuggerWasDisabled();
   1562 }
   1563 
   1564 void InspectorController::resumeDebugger()
   1565 {
   1566     if (!m_debuggerEnabled)
   1567         return;
   1568     JavaScriptDebugServer::shared().continueProgram();
   1569 }
   1570 
   1571 // JavaScriptDebugListener functions
   1572 
   1573 void InspectorController::didParseSource(ExecState*, const SourceCode& source)
   1574 {
   1575     m_frontend->parsedScriptSource(source);
   1576 }
   1577 
   1578 void InspectorController::failedToParseSource(ExecState*, const SourceCode& source, int errorLine, const UString& errorMessage)
   1579 {
   1580     m_frontend->failedToParseScriptSource(source, errorLine, errorMessage);
   1581 }
   1582 
   1583 void InspectorController::didPause()
   1584 {
   1585     JavaScriptCallFrame* callFrame = m_injectedScriptHost->currentCallFrame();
   1586     ScriptState* scriptState = callFrame->scopeChain()->globalObject->globalExec();
   1587     ASSERT(scriptState);
   1588     InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(scriptState);
   1589     RefPtr<SerializedScriptValue> callFrames = injectedScript.callFrames();
   1590     m_frontend->pausedScript(callFrames.get());
   1591 }
   1592 
   1593 void InspectorController::didContinue()
   1594 {
   1595     m_frontend->resumedScript();
   1596 }
   1597 
   1598 #endif
   1599 
   1600 void InspectorController::evaluateForTestInFrontend(long callId, const String& script)
   1601 {
   1602     if (m_frontend)
   1603         m_frontend->evaluateForTestInFrontend(callId, script);
   1604     else
   1605         m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
   1606 }
   1607 
   1608 void InspectorController::didEvaluateForTestInFrontend(long callId, const String& jsonResult)
   1609 {
   1610     ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
   1611     ScriptObject window;
   1612     ScriptGlobalObject::get(scriptState, "window", window);
   1613     ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
   1614     function.appendArgument(callId);
   1615     function.appendArgument(jsonResult);
   1616     function.call();
   1617 }
   1618 
   1619 static Path quadToPath(const FloatQuad& quad)
   1620 {
   1621     Path quadPath;
   1622     quadPath.moveTo(quad.p1());
   1623     quadPath.addLineTo(quad.p2());
   1624     quadPath.addLineTo(quad.p3());
   1625     quadPath.addLineTo(quad.p4());
   1626     quadPath.closeSubpath();
   1627     return quadPath;
   1628 }
   1629 
   1630 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
   1631 {
   1632     static const int outlineThickness = 2;
   1633     static const Color outlineColor(62, 86, 180, 228);
   1634 
   1635     Path quadPath = quadToPath(quad);
   1636 
   1637     // Clip out the quad, then draw with a 2px stroke to get a pixel
   1638     // of outline (because inflating a quad is hard)
   1639     {
   1640         context.save();
   1641         context.addPath(quadPath);
   1642         context.clipOut(quadPath);
   1643 
   1644         context.addPath(quadPath);
   1645         context.setStrokeThickness(outlineThickness);
   1646         context.setStrokeColor(outlineColor, DeviceColorSpace);
   1647         context.strokePath();
   1648 
   1649         context.restore();
   1650     }
   1651 
   1652     // Now do the fill
   1653     context.addPath(quadPath);
   1654     context.setFillColor(fillColor, DeviceColorSpace);
   1655     context.fillPath();
   1656 }
   1657 
   1658 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
   1659 {
   1660     context.save();
   1661     Path clipQuadPath = quadToPath(clipQuad);
   1662     context.clipOut(clipQuadPath);
   1663     drawOutlinedQuad(context, quad, fillColor);
   1664     context.restore();
   1665 }
   1666 
   1667 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
   1668 {
   1669     static const Color contentBoxColor(125, 173, 217, 128);
   1670     static const Color paddingBoxColor(125, 173, 217, 160);
   1671     static const Color borderBoxColor(125, 173, 217, 192);
   1672     static const Color marginBoxColor(125, 173, 217, 228);
   1673 
   1674     if (marginQuad != borderQuad)
   1675         drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
   1676     if (borderQuad != paddingQuad)
   1677         drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
   1678     if (paddingQuad != contentQuad)
   1679         drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
   1680 
   1681     drawOutlinedQuad(context, contentQuad, contentBoxColor);
   1682 }
   1683 
   1684 static void drawHighlightForLineBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
   1685 {
   1686     static const Color lineBoxColor(125, 173, 217, 128);
   1687 
   1688     for (size_t i = 0; i < lineBoxQuads.size(); ++i)
   1689         drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
   1690 }
   1691 
   1692 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
   1693 {
   1694     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
   1695 }
   1696 
   1697 static inline IntSize frameToMainFrameOffset(Frame* frame)
   1698 {
   1699     IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
   1700     return mainFramePoint - IntPoint();
   1701 }
   1702 
   1703 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
   1704 {
   1705     if (!m_highlightedNode)
   1706         return;
   1707 
   1708     RenderObject* renderer = m_highlightedNode->renderer();
   1709     Frame* containingFrame = m_highlightedNode->document()->frame();
   1710     if (!renderer || !containingFrame)
   1711         return;
   1712 
   1713     IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
   1714     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
   1715     boundingBox.move(mainFrameOffset);
   1716 
   1717     ASSERT(m_inspectedPage);
   1718 
   1719     FrameView* view = m_inspectedPage->mainFrame()->view();
   1720     FloatRect overlayRect = view->visibleContentRect();
   1721     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
   1722         overlayRect = view->visibleContentRect();
   1723     context.translate(-overlayRect.x(), -overlayRect.y());
   1724 
   1725     if (renderer->isBox()) {
   1726         RenderBox* renderBox = toRenderBox(renderer);
   1727 
   1728         IntRect contentBox = renderBox->contentBoxRect();
   1729 
   1730         IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
   1731                            contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
   1732         IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
   1733                           paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
   1734         IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
   1735                           borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
   1736 
   1737         FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
   1738         FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
   1739         FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
   1740         FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
   1741 
   1742         absContentQuad.move(mainFrameOffset);
   1743         absPaddingQuad.move(mainFrameOffset);
   1744         absBorderQuad.move(mainFrameOffset);
   1745         absMarginQuad.move(mainFrameOffset);
   1746 
   1747         drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
   1748     } else if (renderer->isRenderInline()) {
   1749         RenderInline* renderInline = toRenderInline(renderer);
   1750 
   1751         // FIXME: We should show margins/padding/border for inlines.
   1752         Vector<FloatQuad> lineBoxQuads;
   1753         renderInline->absoluteQuads(lineBoxQuads);
   1754         for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
   1755             lineBoxQuads[i] += mainFrameOffset;
   1756 
   1757         drawHighlightForLineBoxes(context, lineBoxQuads);
   1758     }
   1759 }
   1760 
   1761 void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID)
   1762 {
   1763     String identifier = title + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
   1764     HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
   1765     int count;
   1766     if (it == m_counts.end())
   1767         count = 1;
   1768     else {
   1769         count = it->second + 1;
   1770         m_counts.remove(it);
   1771     }
   1772 
   1773     m_counts.add(identifier, count);
   1774 
   1775     String message = String::format("%s: %d", title.utf8().data(), count);
   1776     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceID);
   1777 }
   1778 
   1779 void InspectorController::startTiming(const String& title)
   1780 {
   1781     m_times.add(title, currentTime() * 1000);
   1782 }
   1783 
   1784 bool InspectorController::stopTiming(const String& title, double& elapsed)
   1785 {
   1786     HashMap<String, double>::iterator it = m_times.find(title);
   1787     if (it == m_times.end())
   1788         return false;
   1789 
   1790     double startTime = it->second;
   1791     m_times.remove(it);
   1792 
   1793     elapsed = currentTime() * 1000 - startTime;
   1794     return true;
   1795 }
   1796 
   1797 InspectorController::SpecialPanels InspectorController::specialPanelForJSName(const String& panelName)
   1798 {
   1799     if (panelName == "elements")
   1800         return ElementsPanel;
   1801     if (panelName == "resources")
   1802         return ResourcesPanel;
   1803     if (panelName == "scripts")
   1804         return ScriptsPanel;
   1805     if (panelName == "timeline")
   1806         return TimelinePanel;
   1807     if (panelName == "profiles")
   1808         return ProfilesPanel;
   1809     if (panelName == "storage" || panelName == "databases")
   1810         return StoragePanel;
   1811     if (panelName == "console")
   1812         return ConsolePanel;
   1813     return ElementsPanel;
   1814 }
   1815 
   1816 void InspectorController::deleteCookie(const String& cookieName, const String& domain)
   1817 {
   1818     ResourcesMap::iterator resourcesEnd = m_resources.end();
   1819     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
   1820         Document* document = it->second->frame()->document();
   1821         if (document->url().host() == domain)
   1822             WebCore::deleteCookie(document, it->second->requestURL(), cookieName);
   1823     }
   1824 }
   1825 
   1826 InjectedScript InspectorController::injectedScriptForNodeId(long id)
   1827 {
   1828 
   1829     Frame* frame = 0;
   1830     if (id) {
   1831         ASSERT(m_domAgent);
   1832         Node* node = m_domAgent->nodeForId(id);
   1833         if (node) {
   1834             Document* document = node->ownerDocument();
   1835             if (document)
   1836                 frame = document->frame();
   1837         }
   1838     } else
   1839         frame = m_inspectedPage->mainFrame();
   1840 
   1841     if (frame)
   1842         return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame));
   1843 
   1844     return InjectedScript();
   1845 }
   1846 
   1847 } // namespace WebCore
   1848 
   1849 #endif // ENABLE(INSPECTOR)
   1850