Home | History | Annotate | Download | only in js
      1 /*
      2  * Copyright (c) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "PageScriptDebugServer.h"
     33 
     34 #if ENABLE(JAVASCRIPT_DEBUGGER)
     35 
     36 #include "Frame.h"
     37 #include "FrameView.h"
     38 #include "JSDOMWindowCustom.h"
     39 #include "Page.h"
     40 #include "PageGroup.h"
     41 #include "PluginView.h"
     42 #include "ScriptDebugListener.h"
     43 #include "Widget.h"
     44 #include <runtime/JSLock.h>
     45 #include <wtf/MainThread.h>
     46 #include <wtf/OwnPtr.h>
     47 #include <wtf/PassOwnPtr.h>
     48 #include <wtf/StdLibExtras.h>
     49 
     50 using namespace JSC;
     51 
     52 namespace WebCore {
     53 
     54 static Page* toPage(JSGlobalObject* globalObject)
     55 {
     56     ASSERT_ARG(globalObject, globalObject);
     57 
     58     JSDOMWindow* window = asJSDOMWindow(globalObject);
     59     Frame* frame = window->impl()->frame();
     60     return frame ? frame->page() : 0;
     61 }
     62 
     63 PageScriptDebugServer& PageScriptDebugServer::shared()
     64 {
     65     DEFINE_STATIC_LOCAL(PageScriptDebugServer, server, ());
     66     return server;
     67 }
     68 
     69 PageScriptDebugServer::PageScriptDebugServer()
     70     : ScriptDebugServer()
     71 {
     72 }
     73 
     74 PageScriptDebugServer::~PageScriptDebugServer()
     75 {
     76     deleteAllValues(m_pageListenersMap);
     77 }
     78 
     79 void PageScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page)
     80 {
     81     ASSERT_ARG(listener, listener);
     82     ASSERT_ARG(page, page);
     83 
     84     pair<PageListenersMap::iterator, bool> result = m_pageListenersMap.add(page, 0);
     85     if (result.second)
     86         result.first->second = new ListenerSet;
     87 
     88     ListenerSet* listeners = result.first->second;
     89     listeners->add(listener);
     90 
     91     recompileAllJSFunctionsSoon();
     92     page->setDebugger(this);
     93 }
     94 
     95 void PageScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page)
     96 {
     97     ASSERT_ARG(listener, listener);
     98     ASSERT_ARG(page, page);
     99 
    100     PageListenersMap::iterator it = m_pageListenersMap.find(page);
    101     if (it == m_pageListenersMap.end())
    102         return;
    103 
    104     ListenerSet* listeners = it->second;
    105     listeners->remove(listener);
    106     if (listeners->isEmpty()) {
    107         m_pageListenersMap.remove(it);
    108         delete listeners;
    109         didRemoveLastListener(page);
    110     }
    111 }
    112 
    113 void PageScriptDebugServer::recompileAllJSFunctions(Timer<ScriptDebugServer>*)
    114 {
    115     JSLock lock(SilenceAssertionsOnly);
    116     // If JavaScript stack is not empty postpone recompilation.
    117     if (JSDOMWindow::commonJSGlobalData()->dynamicGlobalObject)
    118         recompileAllJSFunctionsSoon();
    119     else
    120         Debugger::recompileAllJSFunctions(JSDOMWindow::commonJSGlobalData());
    121 }
    122 
    123 ScriptDebugServer::ListenerSet* PageScriptDebugServer::getListenersForGlobalObject(JSGlobalObject* globalObject)
    124 {
    125     Page* page = toPage(globalObject);
    126     if (!page)
    127         return 0;
    128     return m_pageListenersMap.get(page);
    129 }
    130 
    131 void PageScriptDebugServer::didPause(JSC::JSGlobalObject* globalObject)
    132 {
    133     Page* page = toPage(globalObject);
    134     m_pausedPage = page;
    135     setJavaScriptPaused(page->group(), true);
    136 }
    137 
    138 void PageScriptDebugServer::didContinue(JSC::JSGlobalObject* globalObject)
    139 {
    140     Page* page = toPage(globalObject);
    141     m_pausedPage = 0;
    142     setJavaScriptPaused(page->group(), false);
    143 }
    144 
    145 void PageScriptDebugServer::didRemoveLastListener(Page* page)
    146 {
    147     if (m_pausedPage == page)
    148         m_doneProcessingDebuggerEvents = true;
    149 
    150     recompileAllJSFunctionsSoon();
    151     page->setDebugger(0);
    152 }
    153 
    154 void PageScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused)
    155 {
    156     setMainThreadCallbacksPaused(paused);
    157 
    158     const HashSet<Page*>& pages = pageGroup.pages();
    159 
    160     HashSet<Page*>::const_iterator end = pages.end();
    161     for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it)
    162         setJavaScriptPaused(*it, paused);
    163 }
    164 
    165 void PageScriptDebugServer::setJavaScriptPaused(Page* page, bool paused)
    166 {
    167     ASSERT_ARG(page, page);
    168 
    169     page->setDefersLoading(paused);
    170 
    171     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
    172         setJavaScriptPaused(frame, paused);
    173 }
    174 
    175 void PageScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused)
    176 {
    177     ASSERT_ARG(frame, frame);
    178 
    179     if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript))
    180         return;
    181 
    182     frame->script()->setPaused(paused);
    183 
    184     Document* document = frame->document();
    185     if (paused) {
    186         document->suspendScriptedAnimationControllerCallbacks();
    187         document->suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused);
    188     } else {
    189         document->resumeActiveDOMObjects();
    190         document->resumeScriptedAnimationControllerCallbacks();
    191     }
    192 
    193     setJavaScriptPaused(frame->view(), paused);
    194 }
    195 
    196 void PageScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused)
    197 {
    198     if (!view)
    199         return;
    200 
    201     const HashSet<RefPtr<Widget> >* children = view->children();
    202     ASSERT(children);
    203 
    204     HashSet<RefPtr<Widget> >::const_iterator end = children->end();
    205     for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
    206         Widget* widget = (*it).get();
    207         if (!widget->isPluginView())
    208             continue;
    209         static_cast<PluginView*>(widget)->setJavaScriptPaused(paused);
    210     }
    211 }
    212 
    213 } // namespace WebCore
    214 
    215 #endif // ENABLE(JAVASCRIPT_DEBUGGER)
    216