Make it possible for JavaScriptDebugListeners to listen to specific Pages
authoraroben@apple.com <aroben@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Apr 2008 17:59:44 +0000 (17:59 +0000)
committeraroben@apple.com <aroben@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Apr 2008 17:59:44 +0000 (17:59 +0000)
        JavaScriptDebugServer now has overloads of its
        addListener/removeListener methods that take a Page* to indicate for
        which Page the JavaScriptDebugListener wishes to receive messages.

        Reviewed by Darin.

        * page/JavaScriptDebugServer.cpp:
        (WebCore::JavaScriptDebugServer::~JavaScriptDebugServer): Delete all
        ListenerSets being held in m_pageListenersMap.
        (WebCore::JavaScriptDebugServer::addListener): Changed to call
        hasListeners().
        (WebCore::JavaScriptDebugServer::removeListener): Ditto.
        (WebCore::JavaScriptDebugServer::addListener): Added. This overload
        takes a Page* and puts the listener in the appropriate ListenerSet
        within m_pageListenersMap. The ListenerSet is allocated and added to
        m_pageListenersMap when its first listener is added.
        (WebCore::JavaScriptDebugServer::removeListener): Added. This overload
        takes a Page* and removes the listener from the appropriate
        ListenerSet in m_pageListenersMap. The ListenerSet is deleted and
        removed from m_pageListenersMap when its last listener is removed.
        (WebCore::toPage): Added. Retrieves the parent Page from an ExecState.
        (WebCore::JavaScriptDebugServer::sourceParsed): Changed to call
        dispatchDidParseSource/dispatchDidFailToParseSource for both the
        global listeners and the Page listeners.
        (WebCore::dispatchFunctionToListeners): Added. This code was extracted
        from the JavaScriptDebugServer method of the same name.
        (WebCore::JavaScriptDebugServer::dispatchFunctionToListeners): Call
        dispatchFunctionToListeners for both the global listeners and the Page
        listeners.
        * page/JavaScriptDebugServer.h:
          - Added declarations for new methods.
          - Made JavaScriptExecutionCallback typedef public so that it could
            be used by a helper method.
          - Added new m_pageListenersMap member.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@31570 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/page/JavaScriptDebugServer.cpp
WebCore/page/JavaScriptDebugServer.h

index a1b9255..415d2ff 100644 (file)
@@ -1,3 +1,41 @@
+2008-04-02  Adam Roben  <aroben@apple.com>
+
+        Make it possible for JavaScriptDebugListeners to listen to specific Pages
+
+        JavaScriptDebugServer now has overloads of its
+        addListener/removeListener methods that take a Page* to indicate for
+        which Page the JavaScriptDebugListener wishes to receive messages.
+
+        Reviewed by Darin.
+
+        * page/JavaScriptDebugServer.cpp:
+        (WebCore::JavaScriptDebugServer::~JavaScriptDebugServer): Delete all
+        ListenerSets being held in m_pageListenersMap.
+        (WebCore::JavaScriptDebugServer::addListener): Changed to call
+        hasListeners().
+        (WebCore::JavaScriptDebugServer::removeListener): Ditto.
+        (WebCore::JavaScriptDebugServer::addListener): Added. This overload
+        takes a Page* and puts the listener in the appropriate ListenerSet
+        within m_pageListenersMap. The ListenerSet is allocated and added to
+        m_pageListenersMap when its first listener is added.
+        (WebCore::JavaScriptDebugServer::removeListener): Added. This overload
+        takes a Page* and removes the listener from the appropriate
+        ListenerSet in m_pageListenersMap. The ListenerSet is deleted and
+        removed from m_pageListenersMap when its last listener is removed.
+        (WebCore::toPage): Added. Retrieves the parent Page from an ExecState.
+        (WebCore::JavaScriptDebugServer::sourceParsed): Changed to call
+        dispatchDidParseSource/dispatchDidFailToParseSource for both the
+        global listeners and the Page listeners.
+        (WebCore::dispatchFunctionToListeners): Added. This code was extracted
+        from the JavaScriptDebugServer method of the same name.
+        (WebCore::JavaScriptDebugServer::dispatchFunctionToListeners): Call
+        dispatchFunctionToListeners for both the global listeners and the Page
+        listeners.
+        * page/JavaScriptDebugServer.h:
+          - Added declarations for new methods.
+          - Made JavaScriptExecutionCallback typedef public so that it could
+            be used by a helper method.
+          - Added new m_pageListenersMap member.
 2008-04-02  Simon Hausmann  <hausmann@webkit.org>
 
         Fix compilation on case-sensitive file systems.
index bd324aa..5bf0e82 100644 (file)
@@ -54,11 +54,12 @@ JavaScriptDebugServer::JavaScriptDebugServer()
 
 JavaScriptDebugServer::~JavaScriptDebugServer()
 {
+    deleteAllValues(m_pageListenersMap);
 }
 
 void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener)
 {
-    if (m_listeners.isEmpty())
+    if (!hasListeners())
         Page::setDebuggerForAllPages(this);
 
     m_listeners.add(listener);
@@ -67,13 +68,49 @@ void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener)
 void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener)
 {
     m_listeners.remove(listener);
-    if (m_listeners.isEmpty())
+    if (!hasListeners())
+        Page::setDebuggerForAllPages(0);
+}
+
+void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener, Page* page)
+{
+    ASSERT_ARG(page, page);
+
+    if (!hasListeners())
+        Page::setDebuggerForAllPages(this);
+
+    pair<PageListenersMap::iterator, bool> result = m_pageListenersMap.add(page, 0);
+    if (result.second)
+        result.first->second = new ListenerSet;
+    ListenerSet* listeners = result.first->second;
+
+    listeners->add(listener);
+}
+
+void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener, Page* page)
+{
+    ASSERT_ARG(page, page);
+
+    PageListenersMap::iterator it = m_pageListenersMap.find(page);
+    if (it == m_pageListenersMap.end())
+        return;
+
+    ListenerSet* listeners = it->second;
+
+    listeners->remove(listener);
+
+    if (listeners->isEmpty()) {
+        m_pageListenersMap.remove(it);
+        delete listeners;
+    }
+
+    if (!hasListeners())
         Page::setDebuggerForAllPages(0);
 }
 
 void JavaScriptDebugServer::pageCreated(Page* page)
 {
-    if (m_listeners.isEmpty())
+    if (!hasListeners())
         return;
 
     page->setDebugger(this);
@@ -95,33 +132,76 @@ static void dispatchFailedToParseSource(const ListenerSet& listeners, ExecState*
         copy[i]->failedToParseSource(state, source, startingLineNumber, sourceURL, errorLine, errorMessage);
 }
 
+static Page* toPage(ExecState* state)
+{
+    ASSERT_ARG(state, state);
+
+    JSDOMWindow* window = toJSDOMWindow(state->dynamicGlobalObject());
+    ASSERT(window);
+
+    return window->impl()->frame()->page();
+}
+
 bool JavaScriptDebugServer::sourceParsed(ExecState* state, int sourceID, const UString& sourceURL, const UString& source, int startingLineNumber, int errorLine, const UString& errorMessage)
 {
     if (m_callingListeners)
         return true;
+
+    Page* page = toPage(state);
+    if (!page)
+        return true;
+
     m_callingListeners = true;
 
-    ASSERT(!m_listeners.isEmpty());
-    if (errorLine == -1)
-        dispatchDidParseSource(m_listeners, state, source, startingLineNumber, sourceURL, sourceID);
-    else
-        dispatchFailedToParseSource(m_listeners, state, source, startingLineNumber, sourceURL, errorLine, errorMessage);
+    ASSERT(hasListeners());
+
+    bool isError = errorLine != -1;
+
+    if (!m_listeners.isEmpty()) {
+        if (isError)
+            dispatchFailedToParseSource(m_listeners, state, source, startingLineNumber, sourceURL, errorLine, errorMessage);
+        else
+            dispatchDidParseSource(m_listeners, state, source, startingLineNumber, sourceURL, sourceID);
+    }
+
+    if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
+        ASSERT(!pageListeners->isEmpty());
+        if (isError)
+            dispatchFailedToParseSource(*pageListeners, state, source, startingLineNumber, sourceURL, errorLine, errorMessage);
+        else
+            dispatchDidParseSource(*pageListeners, state, source, startingLineNumber, sourceURL, sourceID);
+    }
 
     m_callingListeners = false;
     return true;
 }
 
+static void dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptDebugServer::JavaScriptExecutionCallback callback, ExecState* state, int sourceID, int lineNumber)
+{
+    Vector<JavaScriptDebugListener*> copy;
+    copyToVector(listeners, copy);
+    for (size_t i = 0; i < copy.size(); ++i)
+        (copy[i]->*callback)(state, sourceID, lineNumber);
+}
+
 void JavaScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, ExecState* state, int sourceID, int lineNumber)
 {
     if (m_callingListeners)
         return;
+
+    Page* page = toPage(state);
+    if (!page)
+        return;
+
     m_callingListeners = true;
 
-    ASSERT(!m_listeners.isEmpty());
-    Vector<JavaScriptDebugListener*> copy;
-    copyToVector(m_listeners, copy);
-    for (size_t i = 0; i < copy.size(); ++i)
-        (copy[i]->*callback)(state, sourceID, lineNumber);
+    ASSERT(hasListeners());
+
+    WebCore::dispatchFunctionToListeners(m_listeners, callback, state, sourceID, lineNumber);
+    if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
+        ASSERT(!pageListeners->isEmpty());
+        WebCore::dispatchFunctionToListeners(*pageListeners, callback, state, sourceID, lineNumber);
+    }
 
     m_callingListeners = false;
 }
index 3301fd8..2b57f26 100644 (file)
@@ -47,15 +47,20 @@ namespace WebCore {
         void addListener(JavaScriptDebugListener*);
         void removeListener(JavaScriptDebugListener*);
 
+        void addListener(JavaScriptDebugListener*, Page*);
+        void removeListener(JavaScriptDebugListener*, Page*);
+
         void pageCreated(Page*);
 
         typedef HashSet<JavaScriptDebugListener*> ListenerSet;
+        typedef void (JavaScriptDebugListener::*JavaScriptExecutionCallback)(KJS::ExecState*, int sourceID, int lineNumber);
 
     private:
         JavaScriptDebugServer();
         ~JavaScriptDebugServer();
 
-        typedef void (JavaScriptDebugListener::*JavaScriptExecutionCallback)(KJS::ExecState*, int sourceID, int lineNumber);
+        bool hasListeners() const { return !m_listeners.isEmpty() || !m_pageListenersMap.isEmpty(); }
+
         void dispatchFunctionToListeners(JavaScriptExecutionCallback, KJS::ExecState*, int sourceID, int lineNumber);
 
         virtual bool sourceParsed(KJS::ExecState*, int sourceID, const KJS::UString& sourceURL, const KJS::UString& source, int startingLineNumber, int errorLine, const KJS::UString& errorMsg);
@@ -64,6 +69,8 @@ namespace WebCore {
         virtual bool returnEvent(KJS::ExecState*, int sourceID, int lineNumber, KJS::JSObject* function);
         virtual bool exception(KJS::ExecState*, int sourceID, int lineNumber, KJS::JSValue* exception);
 
+        typedef HashMap<Page*, ListenerSet*> PageListenersMap;
+        PageListenersMap m_pageListenersMap;
         ListenerSet m_listeners;
         bool m_callingListeners;
     };