2011-02-01 Pavel Podivilov <podivilov@chromium.org>
authorpodivilov@chromium.org <podivilov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Feb 2011 15:24:41 +0000 (15:24 +0000)
committerpodivilov@chromium.org <podivilov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Feb 2011 15:24:41 +0000 (15:24 +0000)
        Reviewed by Pavel Feldman.

        Web Inspector: introduce new api for managing JavaScript breakpoints.
        https://bugs.webkit.org/show_bug.cgi?id=53235

        * inspector/report-protocol-errors.html:
2011-02-01  Pavel Podivilov  <podivilov@chromium.org>

        Reviewed by Pavel Feldman.

        Web Inspector: introduce new api for managing JavaScript breakpoints.
        https://bugs.webkit.org/show_bug.cgi?id=53235

        Single protocol breakpoint (e.g. set by url) is mapped on zero or more VM breakpoints (set by sourceID).
        removeJavaScriptBreakpoint(breakpointId) removes breakpoint and all linked VM breakpoints.
        Since UI uses VM breakpoint location rather then protocol breakpoint location, all resolved breakpoints locations are passed to frontend.

        SourceFrame is now aware of whether breakpoint is resolved or not and may display it accordingly.
        JavaScriptBreakpointsSidebarPane filters out breakpoints set on nonexistent scripts to avoid UI cluttering.

        * bindings/js/ScriptDebugServer.cpp:
        (WebCore::ScriptDebugServer::setBreakpoint):
        (WebCore::ScriptDebugServer::removeBreakpoint):
        * bindings/js/ScriptDebugServer.h:
        * bindings/v8/DebuggerScript.js:
        ():
        * bindings/v8/ScriptDebugServer.cpp:
        (WebCore::ScriptDebugServer::setBreakpoint):
        * bindings/v8/ScriptDebugServer.h:
        * inspector/Inspector.idl:
        * inspector/InspectorAgent.cpp: clear breakpoints from inspector state when new frontend is created
        (WebCore::InspectorAgent::restoreInspectorStateFromCookie):
        (WebCore::InspectorAgent::populateScriptObjects):
        (WebCore::InspectorAgent::restoreDebugger):
        (WebCore::InspectorAgent::showAndEnableDebugger):
        (WebCore::InspectorAgent::enableDebugger):
        * inspector/InspectorAgent.h:
        * inspector/InspectorDebuggerAgent.cpp: manage relations between protocol breakpoints and VM breakpoints
        (WebCore::InspectorDebuggerAgent::InspectorDebuggerAgent):
        (WebCore::InspectorDebuggerAgent::inspectedURLChanged):
        (WebCore::InspectorDebuggerAgent::setJavaScriptBreakpoint):
        (WebCore::InspectorDebuggerAgent::setJavaScriptBreakpointBySourceId):
        (WebCore::InspectorDebuggerAgent::removeJavaScriptBreakpoint):
        (WebCore::InspectorDebuggerAgent::continueToLocation):
        (WebCore::InspectorDebuggerAgent::resolveBreakpoint):
        (WebCore::InspectorDebuggerAgent::getScriptSource):
        (WebCore::InspectorDebuggerAgent::didParseSource):
        (WebCore::InspectorDebuggerAgent::didPause):
        * inspector/InspectorDebuggerAgent.h:
        (WebCore::InspectorDebuggerAgent::Script::Script):
        * inspector/InspectorValues.cpp:
        (WebCore::InspectorValue::asNumber):
        (WebCore::InspectorBasicValue::asNumber):
        (WebCore::InspectorObject::remove):
        * inspector/InspectorValues.h:
        (WebCore::InspectorObject::getNumber):
        (WebCore::InspectorObject::find):
        * inspector/ScriptBreakpoint.h:
        (WebCore::ScriptBreakpoint::ScriptBreakpoint):
        * inspector/front-end/Breakpoint.js:
        (WebInspector.Breakpoint):
        (WebInspector.Breakpoint.prototype.addLocation):
        * inspector/front-end/BreakpointManager.js: remove all stuff related to JavaScript breakpoints from here
        (WebInspector.BreakpointManager):
        (WebInspector.BreakpointManager.prototype._projectChanged):
        (WebInspector.BreakpointManager.prototype._saveBreakpoints):
        (WebInspector.BreakpointManager.prototype._validateBreakpoints):
        * inspector/front-end/BreakpointsSidebarPane.js:
        (WebInspector.JavaScriptBreakpointsSidebarPane): filter breakpoints set on nonexistent scripts to avoid ui cluttering
        * inspector/front-end/DebuggerModel.js:
        (WebInspector.DebuggerModel): pull all JavaScript from localStorage and push them to fronted when debugger is enabled, save resolved breakpoints data
        * inspector/front-end/Script.js:
        (WebInspector.Script.prototype.sourceLine):
        * inspector/front-end/ScriptsPanel.js:
        (WebInspector.ScriptsPanel.prototype._toggleDebugging):
        * inspector/front-end/Settings.js:
        (WebInspector.Settings):
        * inspector/front-end/SourceFrame.js: handle resolved and unresolved breakpoints differently
        * inspector/front-end/inspector.js:
2011-02-01  Pavel Podivilov  <podivilov@chromium.org>

        Reviewed by Pavel Feldman.

        Web Inspector: introduce new api for managing JavaScript breakpoints.
        https://bugs.webkit.org/show_bug.cgi?id=53235

        * src/WebDevToolsAgentImpl.cpp:
        (WebKit::WebDevToolsAgent::shouldInterruptForMessage):

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

27 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/report-protocol-errors.html
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/ScriptDebugServer.cpp
Source/WebCore/bindings/js/ScriptDebugServer.h
Source/WebCore/bindings/v8/DebuggerScript.js
Source/WebCore/bindings/v8/ScriptDebugServer.cpp
Source/WebCore/bindings/v8/ScriptDebugServer.h
Source/WebCore/inspector/Inspector.idl
Source/WebCore/inspector/InspectorAgent.cpp
Source/WebCore/inspector/InspectorAgent.h
Source/WebCore/inspector/InspectorDebuggerAgent.cpp
Source/WebCore/inspector/InspectorDebuggerAgent.h
Source/WebCore/inspector/InspectorValues.cpp
Source/WebCore/inspector/InspectorValues.h
Source/WebCore/inspector/ScriptBreakpoint.h
Source/WebCore/inspector/front-end/Breakpoint.js
Source/WebCore/inspector/front-end/BreakpointManager.js
Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js
Source/WebCore/inspector/front-end/DebuggerModel.js
Source/WebCore/inspector/front-end/Script.js
Source/WebCore/inspector/front-end/ScriptsPanel.js
Source/WebCore/inspector/front-end/Settings.js
Source/WebCore/inspector/front-end/SourceFrame.js
Source/WebCore/inspector/front-end/inspector.js
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/src/WebDevToolsAgentImpl.cpp

index b518a0e..5c15ec4 100644 (file)
@@ -1,3 +1,12 @@
+2011-02-01  Pavel Podivilov  <podivilov@chromium.org>
+
+        Reviewed by Pavel Feldman.
+
+        Web Inspector: introduce new api for managing JavaScript breakpoints.
+        https://bugs.webkit.org/show_bug.cgi?id=53235
+
+        * inspector/report-protocol-errors.html:
+
 2011-02-03  Philippe Normand  <pnormand@igalia.com>
 
         Unreviewed, skip flaky websocket tests on GTK
index 1827be0..c989c10 100644 (file)
@@ -16,8 +16,8 @@ function test()
         '{"seq":3,"command":"resourceContent","arguments":[]}',
         '{"seq":4,"command":"resourceContent","arguments":{}}',
         '{"seq":5,"command":"resourceContent","arguments":{"identifier":"not a number"}}',
-        '{"seq":6,"command":"removeBreakpoint","arguments":{}}',
-        '{"seq":7,"command":"removeBreakpoint","arguments":{"breakpointId":"someBreakpointId"}}',
+        '{"seq":6,"command":"removeJavaScriptBreakpoint","arguments":{}}',
+        '{"seq":7,"command":"removeJavaScriptBreakpoint","arguments":{"breakpointId":"someBreakpointId"}}',
     ];
     var numberOfReports = 0;
 
index bdf3ff0..def8ba0 100644 (file)
@@ -1,3 +1,77 @@
+2011-02-01  Pavel Podivilov  <podivilov@chromium.org>
+
+        Reviewed by Pavel Feldman.
+
+        Web Inspector: introduce new api for managing JavaScript breakpoints.
+        https://bugs.webkit.org/show_bug.cgi?id=53235
+
+        Single protocol breakpoint (e.g. set by url) is mapped on zero or more VM breakpoints (set by sourceID).
+        removeJavaScriptBreakpoint(breakpointId) removes breakpoint and all linked VM breakpoints.
+        Since UI uses VM breakpoint location rather then protocol breakpoint location, all resolved breakpoints locations are passed to frontend.
+
+        SourceFrame is now aware of whether breakpoint is resolved or not and may display it accordingly.
+        JavaScriptBreakpointsSidebarPane filters out breakpoints set on nonexistent scripts to avoid UI cluttering.
+
+        * bindings/js/ScriptDebugServer.cpp:
+        (WebCore::ScriptDebugServer::setBreakpoint):
+        (WebCore::ScriptDebugServer::removeBreakpoint):
+        * bindings/js/ScriptDebugServer.h:
+        * bindings/v8/DebuggerScript.js:
+        ():
+        * bindings/v8/ScriptDebugServer.cpp:
+        (WebCore::ScriptDebugServer::setBreakpoint):
+        * bindings/v8/ScriptDebugServer.h:
+        * inspector/Inspector.idl:
+        * inspector/InspectorAgent.cpp: clear breakpoints from inspector state when new frontend is created
+        (WebCore::InspectorAgent::restoreInspectorStateFromCookie):
+        (WebCore::InspectorAgent::populateScriptObjects):
+        (WebCore::InspectorAgent::restoreDebugger):
+        (WebCore::InspectorAgent::showAndEnableDebugger):
+        (WebCore::InspectorAgent::enableDebugger):
+        * inspector/InspectorAgent.h:
+        * inspector/InspectorDebuggerAgent.cpp: manage relations between protocol breakpoints and VM breakpoints
+        (WebCore::InspectorDebuggerAgent::InspectorDebuggerAgent):
+        (WebCore::InspectorDebuggerAgent::inspectedURLChanged):
+        (WebCore::InspectorDebuggerAgent::setJavaScriptBreakpoint):
+        (WebCore::InspectorDebuggerAgent::setJavaScriptBreakpointBySourceId):
+        (WebCore::InspectorDebuggerAgent::removeJavaScriptBreakpoint):
+        (WebCore::InspectorDebuggerAgent::continueToLocation):
+        (WebCore::InspectorDebuggerAgent::resolveBreakpoint):
+        (WebCore::InspectorDebuggerAgent::getScriptSource):
+        (WebCore::InspectorDebuggerAgent::didParseSource):
+        (WebCore::InspectorDebuggerAgent::didPause):
+        * inspector/InspectorDebuggerAgent.h:
+        (WebCore::InspectorDebuggerAgent::Script::Script):
+        * inspector/InspectorValues.cpp:
+        (WebCore::InspectorValue::asNumber):
+        (WebCore::InspectorBasicValue::asNumber):
+        (WebCore::InspectorObject::remove):
+        * inspector/InspectorValues.h:
+        (WebCore::InspectorObject::getNumber):
+        (WebCore::InspectorObject::find):
+        * inspector/ScriptBreakpoint.h:
+        (WebCore::ScriptBreakpoint::ScriptBreakpoint):
+        * inspector/front-end/Breakpoint.js:
+        (WebInspector.Breakpoint):
+        (WebInspector.Breakpoint.prototype.addLocation):
+        * inspector/front-end/BreakpointManager.js: remove all stuff related to JavaScript breakpoints from here
+        (WebInspector.BreakpointManager):
+        (WebInspector.BreakpointManager.prototype._projectChanged):
+        (WebInspector.BreakpointManager.prototype._saveBreakpoints):
+        (WebInspector.BreakpointManager.prototype._validateBreakpoints):
+        * inspector/front-end/BreakpointsSidebarPane.js:
+        (WebInspector.JavaScriptBreakpointsSidebarPane): filter breakpoints set on nonexistent scripts to avoid ui cluttering
+        * inspector/front-end/DebuggerModel.js:
+        (WebInspector.DebuggerModel): pull all JavaScript from localStorage and push them to fronted when debugger is enabled, save resolved breakpoints data
+        * inspector/front-end/Script.js:
+        (WebInspector.Script.prototype.sourceLine):
+        * inspector/front-end/ScriptsPanel.js:
+        (WebInspector.ScriptsPanel.prototype._toggleDebugging):
+        * inspector/front-end/Settings.js:
+        (WebInspector.Settings):
+        * inspector/front-end/SourceFrame.js: handle resolved and unresolved breakpoints differently
+        * inspector/front-end/inspector.js:
+
 2011-02-03  Nikolas Zimmermann  <nzimmermann@rim.com>
 
         Reviewed by Dirk Schulze.
index 8b45f9b..aed2ad4 100644 (file)
@@ -124,7 +124,7 @@ bool ScriptDebugServer::hasListenersInterestedInPage(Page* page)
     return m_pageListenersMap.contains(page);
 }
 
-String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, long* actualLineNumber, long* actualColumnNumber)
+String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber)
 {
     intptr_t sourceIDValue = sourceID.toIntPtr();
     if (!sourceIDValue)
@@ -132,12 +132,12 @@ String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBrea
     SourceIdToBreakpointsMap::iterator it = m_sourceIdToBreakpoints.find(sourceIDValue);
     if (it == m_sourceIdToBreakpoints.end())
         it = m_sourceIdToBreakpoints.set(sourceIDValue, LineToBreakpointMap()).first;
-    if (it->second.contains(scriptBreakpoint.lineNumber))
+    if (it->second.contains(scriptBreakpoint.lineNumber + 1))
         return "";
-    it->second.set(scriptBreakpoint.lineNumber, scriptBreakpoint);
+    it->second.set(scriptBreakpoint.lineNumber + 1, scriptBreakpoint);
     *actualLineNumber = scriptBreakpoint.lineNumber;
     // FIXME(WK53003): implement setting breakpoints by line:column.
-    *actualColumnNumber = 1;
+    *actualColumnNumber = 0;
     return makeString(sourceID, ":", String::number(scriptBreakpoint.lineNumber));
 }
 
@@ -156,7 +156,7 @@ void ScriptDebugServer::removeBreakpoint(const String& breakpointId)
         return;
     SourceIdToBreakpointsMap::iterator it = m_sourceIdToBreakpoints.find(sourceIDValue);
     if (it != m_sourceIdToBreakpoints.end())
-        it->second.remove(lineNumber);
+        it->second.remove(lineNumber + 1);
 }
 
 bool ScriptDebugServer::hasBreakpoint(intptr_t sourceID, unsigned lineNumber) const
index 368b07b..428b254 100644 (file)
@@ -64,7 +64,7 @@ public:
     void addListener(ScriptDebugListener*, Page*);
     void removeListener(ScriptDebugListener*, Page*);
 
-    String setBreakpoint(const String& sourceID, const ScriptBreakpoint&, long* actualLineNumber, long* actualColumnNumber);
+    String setBreakpoint(const String& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber);
     void removeBreakpoint(const String& breakpointId);
     void clearBreakpoints();
     void setBreakpointsActivated(bool activated);
index 346974a..1798352 100644 (file)
@@ -91,17 +91,15 @@ DebuggerScript._formatScript = function(script)
 
 DebuggerScript.setBreakpoint = function(execState, args)
 {
-    var lineNumber = DebuggerScript._webkitToV8LineNumber(args.lineNumber);
-    var columnNumber = DebuggerScript._webkitToV8LineNumber(args.columnNumber);
-    var breakId = Debug.setScriptBreakPointById(args.scriptId, lineNumber, columnNumber, args.condition);
+    var breakId = Debug.setScriptBreakPointById(args.scriptId, args.lineNumber, args.columnNumber, args.condition);
     if (!args.enabled)
         Debug.disableScriptBreakPoint(breakId);
 
     var locations = Debug.findBreakPointActualLocations(breakId);
     if (!locations.length)
         return undefined;
-    args.lineNumber = DebuggerScript._v8ToWebkitLineNumber(locations[0].line);
-    args.columnNumber = DebuggerScript._v8ToWebkitLineNumber(locations[0].column);
+    args.lineNumber = locations[0].line;
+    args.columnNumber = locations[0].column;
     return breakId.toString();
 }
 
@@ -265,11 +263,6 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame)
     };
 }
 
-DebuggerScript._webkitToV8LineNumber = function(line)
-{
-    return line - 1;
-};
-
 DebuggerScript._v8ToWebkitLineNumber = function(line)
 {
     return line + 1;
index 11fa860..cc7fba8 100644 (file)
@@ -143,7 +143,7 @@ void ScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page
     // FIXME: Remove all breakpoints set by the agent.
 }
 
-String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, long* actualLineNumber, long* actualColumnNumber)
+String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber)
 {
     v8::HandleScope scope;
     v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
index b4e7390..af3d2ab 100644 (file)
@@ -56,7 +56,7 @@ public:
     void addListener(ScriptDebugListener*, Page*);
     void removeListener(ScriptDebugListener*, Page*);
 
-    String setBreakpoint(const String& sourceID, const ScriptBreakpoint&, long* actualLineNumber, long* actualColumnNumber);
+    String setBreakpoint(const String& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber);
     void removeBreakpoint(const String& breakpointId);
     void clearBreakpoints();
     void setBreakpointsActivated(bool activated);
index cd387c3..a30c9a4 100644 (file)
@@ -250,9 +250,11 @@ module core {
         [domain=Debugger] void activateBreakpoints();
         [domain=Debugger] void deactivateBreakpoints();
 
-        [domain=Debugger] void setAllJavaScriptBreakpoints(in Object breakpoints);
-        [domain=Debugger] void setBreakpoint(in Object breakpoint, out String breakpointId, out long actualLineNumber, out long actualColumnNumber);
-        [domain=Debugger] void removeBreakpoint(in String breakpointId);
+        [domain=Debugger] void setJavaScriptBreakpoint(in String url, in int lineNumber, in int columnNumber, in String condition, in boolean enabled, out String breakpointId, out Array locations);
+        [domain=Debugger] void setJavaScriptBreakpointBySourceId(in String sourceId, in int lineNumber, in int columnNumber, in String condition, in boolean enabled, out String breakpointId, out int actualLineNumber, out int actualColumnNumber);
+        [domain=Debugger] void removeJavaScriptBreakpoint(in String breakpointId);
+        [notify, domain=Debugger] void breakpointResolved(out String breakpointId, out String sourceId, out int lineNumber, out int columnNumber);
+        [domain=Debugger] void continueToLocation(in String sourceId, in int lineNumber, in int columnNumber);
 
         [domain=BrowserDebugger] void setAllBrowserBreakpoints(in Object breakpoints);
         [domain=BrowserDebugger] void setDOMBreakpoint(in long nodeId, in long type);
@@ -278,8 +280,6 @@ module core {
         [domain=Debugger] void evaluateOnCallFrame(in Object callFrameId, in String expression, in String objectGroup, in boolean includeCommandLineAPI, out Value result);
         [domain=Debugger] void getCompletionsOnCallFrame(in Object callFrameId, in String expression, in boolean includeCommandLineAPI, out Value result);
 
-        [notify, domain=Debugger] void breakpointResolved(out String breakpointId, out Object breakpoint);
-
 #if defined(ENABLE_WORKERS) && ENABLE_WORKERS
         [notify, domain=Debugger] void didCreateWorker(out long id, out String url, out boolean isShared);
         [notify, domain=Debugger] void didDestroyWorker(out long id);
index 664277e..f35b45d 100644 (file)
@@ -214,7 +214,7 @@ void InspectorAgent::restoreInspectorStateFromCookie(const String& inspectorStat
         startTimelineProfiler();
 
 #if ENABLE(JAVASCRIPT_DEBUGGER)
-    restoreDebugger();
+    restoreDebugger(false);
     restoreProfiler(ProfilerRestoreResetAgent);
     if (m_state->getBoolean(InspectorState::userInitiatedProfiling))
         startUserInitiatedProfiling();
@@ -535,7 +535,7 @@ void InspectorAgent::populateScriptObjects()
         m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
     m_pendingEvaluateTestCommands.clear();
 
-    restoreDebugger();
+    restoreDebugger(true);
     restoreProfiler(ProfilerRestoreNoAction);
 }
 
@@ -562,12 +562,12 @@ void InspectorAgent::pushDataCollectedOffline()
 #endif
 }
 
-void InspectorAgent::restoreDebugger()
+void InspectorAgent::restoreDebugger(bool eraseStickyBreakpoints)
 {
     ASSERT(m_frontend);
 #if ENABLE(JAVASCRIPT_DEBUGGER)
     if (m_state->getBoolean(InspectorState::debuggerEnabled))
-        enableDebugger();
+        enableDebugger(eraseStickyBreakpoints);
 #endif
 }
 
@@ -1006,16 +1006,21 @@ void InspectorAgent::showAndEnableDebugger()
         m_state->setBoolean(InspectorState::debuggerEnabled, true);
         showPanel(ScriptsPanel);
     } else
-        enableDebugger();
+        enableDebugger(true);
 }
 
-void InspectorAgent::enableDebugger()
+void InspectorAgent::enableDebugger(bool eraseStickyBreakpoints)
 {
     if (debuggerEnabled())
         return;
     m_state->setBoolean(InspectorState::debuggerEnabled, true);
     ASSERT(m_inspectedPage);
 
+    if (eraseStickyBreakpoints) {
+        m_state->setObject(InspectorState::javaScriptBreakpoints, InspectorObject::create());
+        m_state->setObject(InspectorState::browserBreakpoints, InspectorObject::create());
+    }
+
     m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend.get());
     m_browserDebuggerAgent = InspectorBrowserDebuggerAgent::create(this);
 
index 8cc49a6..8c83f4d 100644 (file)
@@ -241,7 +241,8 @@ public:
     bool profilerEnabled() const;
 
     void showAndEnableDebugger();
-    void enableDebugger();
+    void enableDebugger() { enableDebugger(false); }
+    void enableDebugger(bool eraseStickyBreakpoints);
     void disableDebugger();
     bool debuggerEnabled() const { return m_debuggerAgent; }
     void resume();
@@ -271,7 +272,7 @@ public:
 
 private:
     void pushDataCollectedOffline();
-    void restoreDebugger();
+    void restoreDebugger(bool eraseStickyBreakpoints);
     enum ProfilerRestoreAction {
         ProfilerRestoreNoAction = 0,
         ProfilerRestoreResetAgent = 1
index 3c62981..e96c22b 100644 (file)
@@ -38,6 +38,7 @@
 #include "InspectorValues.h"
 #include "PlatformString.h"
 #include "ScriptDebugServer.h"
+#include <wtf/text/StringConcatenate.h>
 
 namespace WebCore {
 
@@ -56,7 +57,6 @@ InspectorDebuggerAgent::InspectorDebuggerAgent(InspectorAgent* inspectorAgent, I
     , m_frontend(frontend)
     , m_pausedScriptState(0)
     , m_javaScriptPauseScheduled(false)
-    , m_breakpointsRestored(false)
 {
 }
 
@@ -76,111 +76,107 @@ void InspectorDebuggerAgent::deactivateBreakpoints()
     ScriptDebugServer::shared().deactivateBreakpoints();
 }
 
-void InspectorDebuggerAgent::setAllJavaScriptBreakpoints(PassRefPtr<InspectorObject> breakpoints)
+void InspectorDebuggerAgent::inspectedURLChanged(const String&)
 {
-    m_inspectorAgent->state()->setObject(InspectorState::javaScriptBreakpoints, breakpoints);
-    if (!m_breakpointsRestored) {
-        restoreBreakpoints(m_inspectorAgent->inspectedURLWithoutFragment());
-        m_breakpointsRestored = true;
-    }
-}
-
-void InspectorDebuggerAgent::inspectedURLChanged(const String& url)
-{
-    m_scriptIDToContent.clear();
-    m_urlToSourceIDs.clear();
-    restoreBreakpoints(url);
+    m_scripts.clear();
+    m_breakpointIdToDebugServerBreakpointIds.clear();
 }
 
-void InspectorDebuggerAgent::restoreBreakpoints(const String& inspectedURL)
+void InspectorDebuggerAgent::setJavaScriptBreakpoint(const String& url, int lineNumber, int columnNumber, const String& condition, bool enabled, String* outBreakpointId, RefPtr<InspectorArray>* locations)
 {
-    m_stickyBreakpoints.clear();
-
-    RefPtr<InspectorObject> allBreakpoints = m_inspectorAgent->state()->getObject(InspectorState::javaScriptBreakpoints);
-    RefPtr<InspectorArray> breakpoints = allBreakpoints->getArray(inspectedURL);
-    if (!breakpoints)
+    String breakpointId = makeString(url, ":", String::number(lineNumber), ":", String::number(columnNumber));
+    RefPtr<InspectorObject> breakpointsCookie = m_inspectorAgent->state()->getObject(InspectorState::javaScriptBreakpoints);
+    if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end())
         return;
-    for (unsigned i = 0; i < breakpoints->length(); ++i) {
-        RefPtr<InspectorObject> breakpoint = breakpoints->get(i)->asObject();
-        if (!breakpoint)
-            continue;
-        String url;
-        if (!breakpoint->getString("url", &url))
-            continue;
-        double lineNumber;
-        if (!breakpoint->getNumber("lineNumber", &lineNumber))
+    RefPtr<InspectorObject> breakpointObject = InspectorObject::create();
+    breakpointObject->setString("url", url);
+    breakpointObject->setNumber("lineNumber", lineNumber);
+    breakpointObject->setNumber("columnNumber", columnNumber);
+    breakpointObject->setString("condition", condition);
+    breakpointObject->setBoolean("enabled", enabled);
+    breakpointsCookie->setObject(breakpointId, breakpointObject);
+    m_inspectorAgent->state()->setObject(InspectorState::javaScriptBreakpoints, breakpointsCookie);
+
+    ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition, enabled);
+    for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) {
+        if (it->second.url != url)
             continue;
-        double columnNumber;
-        if (!breakpoint->getNumber("columnNumber", &columnNumber))
-            return;
-        String condition;
-        if (!breakpoint->getString("condition", &condition))
+        int actualLineNumber = 0, actualColumnNumber = 0;
+        if (!resolveBreakpoint(breakpointId, it->first, breakpoint, &actualLineNumber, &actualColumnNumber))
             continue;
-        bool enabled;
-        if (!breakpoint->getBoolean("enabled", &enabled))
-            continue;
-        ScriptBreakpoint scriptBreakpoint((long) lineNumber, (long) columnNumber, condition, enabled);
-        setStickyBreakpoint(url, scriptBreakpoint);
+        RefPtr<InspectorObject> location = InspectorObject::create();
+        location->setString("sourceID", it->first);
+        location->setNumber("lineNumber", actualLineNumber);
+        location->setNumber("columnNumber", actualColumnNumber);
+        locations->get()->pushObject(location);
     }
+    *outBreakpointId = breakpointId;
 }
 
-void InspectorDebuggerAgent::setStickyBreakpoint(const String& url, const ScriptBreakpoint& breakpoint)
+void InspectorDebuggerAgent::setJavaScriptBreakpointBySourceId(const String& sourceId, int lineNumber, int columnNumber, const String& condition, bool enabled, String* outBreakpointId, int* actualLineNumber, int* actualColumnNumber)
 {
-    InspectedURLToBreakpointsMap::iterator it = m_stickyBreakpoints.find(url);
-    if (it == m_stickyBreakpoints.end())
-        it = m_stickyBreakpoints.set(url, LocationToBreakpointMap()).first;
-    it->second.set(Location(breakpoint.lineNumber, breakpoint.columnNumber), breakpoint);
-
-    URLToSourceIDsMap::iterator urlToSourceIDsIterator = m_urlToSourceIDs.find(url);
-    if (urlToSourceIDsIterator == m_urlToSourceIDs.end())
+    String breakpointId = makeString(sourceId, ":", String::number(lineNumber), ":", String::number(columnNumber));
+    if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end())
         return;
-    const Vector<String>& sourceIDs = urlToSourceIDsIterator->second;
-    for (size_t i = 0; i < sourceIDs.size(); ++i)
-        restoreBreakpoint(sourceIDs[i], breakpoint);
+    ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition, enabled);
+    if (!resolveBreakpoint(breakpointId, sourceId, breakpoint, actualLineNumber, actualColumnNumber))
+        return;
+    *outBreakpointId = breakpointId;
 }
 
-void InspectorDebuggerAgent::setBreakpoint(PassRefPtr<InspectorObject> breakpoint, String* breakpointId, long* actualLineNumber, long* actualColumnNumber)
+void InspectorDebuggerAgent::removeJavaScriptBreakpoint(const String& breakpointId)
 {
-    String sourceID;
-    if (!breakpoint->getString("sourceID", &sourceID))
-        return;
-    double lineNumber;
-    if (!breakpoint->getNumber("lineNumber", &lineNumber))
-        return;
-    double columnNumber;
-    if (!breakpoint->getNumber("columnNumber", &columnNumber))
-        return;
-    String condition;
-    if (!breakpoint->getString("condition", &condition))
-        return;
-    bool enabled;
-    if (!breakpoint->getBoolean("enabled", &enabled))
+    RefPtr<InspectorObject> breakpointsCookie = m_inspectorAgent->state()->getObject(InspectorState::javaScriptBreakpoints);
+    breakpointsCookie->remove(breakpointId);
+    m_inspectorAgent->state()->setObject(InspectorState::javaScriptBreakpoints, breakpointsCookie);
+
+    BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
+    if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
         return;
-    ScriptBreakpoint scriptBreakpoint((long) lineNumber, (long) columnNumber, condition, enabled);
-    *breakpointId = ScriptDebugServer::shared().setBreakpoint(sourceID, scriptBreakpoint, actualLineNumber, actualColumnNumber);
+    for (size_t i = 0; i < debugServerBreakpointIdsIterator->second.size(); ++i)
+        ScriptDebugServer::shared().removeBreakpoint(debugServerBreakpointIdsIterator->second[i]);
+    m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator);
 }
 
-void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId)
+void InspectorDebuggerAgent::continueToLocation(const String& sourceId, int lineNumber, int columnNumber)
 {
-    ScriptDebugServer::shared().removeBreakpoint(breakpointId);
+    if (!m_continueToLocationBreakpointId.isEmpty()) {
+        ScriptDebugServer::shared().removeBreakpoint(m_continueToLocationBreakpointId);
+        m_continueToLocationBreakpointId = "";
+    }
+    ScriptBreakpoint breakpoint(lineNumber, columnNumber, "", true);
+    m_continueToLocationBreakpointId = ScriptDebugServer::shared().setBreakpoint(sourceId, breakpoint, &lineNumber, &columnNumber);
+    resume();
 }
 
-void InspectorDebuggerAgent::restoreBreakpoint(const String& sourceID, const ScriptBreakpoint& breakpoint)
+bool InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& sourceId, const ScriptBreakpoint& breakpoint, int* actualLineNumber, int* actualColumnNumber)
 {
-    long actualLineNumber = 0, actualColumnNumber = 0;
-    String breakpointId = ScriptDebugServer::shared().setBreakpoint(sourceID, breakpoint, &actualLineNumber, &actualColumnNumber);
-    if (breakpointId.isEmpty())
-        return;
-    RefPtr<InspectorObject> breakpointData = InspectorObject::create();
-    breakpointData->setString("id", breakpointId);
-    breakpointData->setString("sourceID", sourceID);
-    breakpointData->setNumber("lineNumber", actualLineNumber);
-    breakpointData->setNumber("columnNumber", actualColumnNumber);
-    breakpointData->setString("condition", breakpoint.condition);
-    breakpointData->setBoolean("enabled", breakpoint.enabled);
-    breakpointData->setNumber("originalLineNumber", breakpoint.lineNumber);
-    breakpointData->setNumber("originalColumnNumber", breakpoint.columnNumber);
-    m_frontend->breakpointResolved(breakpointId, breakpointData);
+    ScriptsMap::iterator scriptIterator = m_scripts.find(sourceId);
+    if (scriptIterator == m_scripts.end())
+        return false;
+    Script& script = scriptIterator->second;
+    if (breakpoint.lineNumber < script.lineOffset)
+        return false;
+    if (!script.linesCount) {
+        script.linesCount = 1;
+        for (size_t i = 0; i < script.data.length(); ++i) {
+            if (script.data[i] == '\n')
+                script.linesCount += 1;
+        }
+    }
+    if (breakpoint.lineNumber >= script.lineOffset + script.linesCount)
+        return false;
+
+    String debugServerBreakpointId = ScriptDebugServer::shared().setBreakpoint(sourceId, breakpoint, actualLineNumber, actualColumnNumber);
+    if (debugServerBreakpointId.isEmpty())
+        return false;
+
+    BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
+    if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
+        debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).first;
+    debugServerBreakpointIdsIterator->second.append(debugServerBreakpointId);
+
+    return true;
 }
 
 void InspectorDebuggerAgent::editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames)
@@ -191,7 +187,7 @@ void InspectorDebuggerAgent::editScriptSource(const String& sourceID, const Stri
 
 void InspectorDebuggerAgent::getScriptSource(const String& sourceID, String* scriptSource)
 {
-    *scriptSource = m_scriptIDToContent.get(sourceID);
+    *scriptSource = m_scripts.get(sourceID).data;
 }
 
 void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerEventType type, PassRefPtr<InspectorValue> data)
@@ -277,23 +273,27 @@ void InspectorDebuggerAgent::didParseSource(const String& sourceID, const String
     // Don't send script content to the front end until it's really needed.
     m_frontend->parsedScriptSource(sourceID, url, lineOffset, columnOffset, data.length(), worldType);
 
-    m_scriptIDToContent.set(sourceID, data);
+    m_scripts.set(sourceID, Script(url, data, lineOffset, columnOffset));
 
     if (url.isEmpty())
         return;
 
-    URLToSourceIDsMap::iterator urlToSourceIDsIterator = m_urlToSourceIDs.find(url);
-    if (urlToSourceIDsIterator == m_urlToSourceIDs.end())
-        urlToSourceIDsIterator = m_urlToSourceIDs.set(url, Vector<String>()).first;
-    urlToSourceIDsIterator->second.append(sourceID);
-
-    InspectedURLToBreakpointsMap::iterator stickyBreakpointsIterator = m_stickyBreakpoints.find(url);
-    if (stickyBreakpointsIterator == m_stickyBreakpoints.end())
-        return;
-
-    const LocationToBreakpointMap& breakpoints = stickyBreakpointsIterator->second;
-    for (LocationToBreakpointMap::const_iterator it = breakpoints.begin(); it != breakpoints.end(); ++it)
-        restoreBreakpoint(sourceID, it->second);
+    RefPtr<InspectorObject> breakpointsCookie = m_inspectorAgent->state()->getObject(InspectorState::javaScriptBreakpoints);
+    for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
+        RefPtr<InspectorObject> breakpointObject = it->second->asObject();
+        String breakpointURL;
+        breakpointObject->getString("url", &breakpointURL);
+        if (breakpointURL != url)
+            continue;
+        ScriptBreakpoint breakpoint;
+        breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
+        breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
+        breakpointObject->getString("condition", &breakpoint.condition);
+        breakpointObject->getBoolean("enabled", &breakpoint.enabled);
+        int actualLineNumber = 0, actualColumnNumber = 0;
+        if (resolveBreakpoint(it->first, sourceID, breakpoint, &actualLineNumber, &actualColumnNumber))
+            m_frontend->breakpointResolved(it->first, sourceID, actualLineNumber, actualColumnNumber);
+    }
 }
 
 void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
@@ -312,6 +312,11 @@ void InspectorDebuggerAgent::didPause(ScriptState* scriptState)
 
     m_frontend->pausedScript(m_breakProgramDetails);
     m_javaScriptPauseScheduled = false;
+
+    if (!m_continueToLocationBreakpointId.isEmpty()) {
+        ScriptDebugServer::shared().removeBreakpoint(m_continueToLocationBreakpointId);
+        m_continueToLocationBreakpointId = "";
+    }
 }
 
 void InspectorDebuggerAgent::didContinue()
index f0de973..f4e7e41 100644 (file)
@@ -60,15 +60,17 @@ public:
     static PassOwnPtr<InspectorDebuggerAgent> create(InspectorAgent*, InspectorFrontend*);
     virtual ~InspectorDebuggerAgent();
 
-    void setAllJavaScriptBreakpoints(PassRefPtr<InspectorObject>);
     void inspectedURLChanged(const String& url);
 
     // Part of the protocol.
     void activateBreakpoints();
     void deactivateBreakpoints();
-    void setStickyBreakpoint(const String& url, const WebCore::ScriptBreakpoint&);
-    void setBreakpoint(PassRefPtr<InspectorObject> breakpoint, String* breakpointId, long* actualLineNumber, long* actualColumnNumber);
-    void removeBreakpoint(const String& breakpointId);
+
+    void setJavaScriptBreakpoint(const String& url, int lineNumber, int columnNumber, const String& condition, bool enabled, String* breakpointId, RefPtr<InspectorArray>* locations);
+    void setJavaScriptBreakpointBySourceId(const String& sourceId, int lineNumber, int columnNumber, const String& condition, bool enabled, String* breakpointId, int* actualLineNumber, int* actualColumnNumber);
+    void removeJavaScriptBreakpoint(const String& breakpointId);
+    void continueToLocation(const String& sourceId, int lineNumber, int columnNumber);
+
     void editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames);
     void getScriptSource(const String& sourceID, String* scriptSource);
     void schedulePauseOnNextStatement(DebuggerEventType type, PassRefPtr<InspectorValue> data);
@@ -93,23 +95,44 @@ private:
     virtual void didPause(ScriptState*);
     virtual void didContinue();
 
-    void restoreBreakpoints(const String& inspectedURL);
-    void restoreBreakpoint(const String& sourceID, const ScriptBreakpoint&);
-
-    typedef HashMap<String, Vector<String> > URLToSourceIDsMap;
-    typedef std::pair<long, long> Location;
-    typedef HashMap<Location, ScriptBreakpoint> LocationToBreakpointMap;
-    typedef HashMap<String, LocationToBreakpointMap> InspectedURLToBreakpointsMap;
+    bool resolveBreakpoint(const String& breakpointId, const String& sourceId, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber);
+
+    class Script {
+    public:
+        Script()
+            : lineOffset(0)
+            , columnOffset(0)
+            , linesCount(0)
+        {
+        }
+
+        Script(const String& url, const String& data, int lineOffset, int columnOffset)
+            : url(url)
+            , data(data)
+            , lineOffset(lineOffset)
+            , columnOffset(columnOffset)
+            , linesCount(0)
+        {
+        }
+
+        String url;
+        String data;
+        int lineOffset;
+        int columnOffset;
+        int linesCount;
+    };
+
+    typedef HashMap<String, Script> ScriptsMap;
+    typedef HashMap<String, Vector<String> > BreakpointIdToDebugServerBreakpointIdsMap;
 
     InspectorAgent* m_inspectorAgent;
     InspectorFrontend* m_frontend;
     ScriptState* m_pausedScriptState;
-    HashMap<String, String> m_scriptIDToContent;
-    URLToSourceIDsMap m_urlToSourceIDs;
-    InspectedURLToBreakpointsMap m_stickyBreakpoints;
+    ScriptsMap m_scripts;
+    BreakpointIdToDebugServerBreakpointIdsMap m_breakpointIdToDebugServerBreakpointIds;
+    String m_continueToLocationBreakpointId;
     RefPtr<InspectorObject> m_breakProgramDetails;
     bool m_javaScriptPauseScheduled;
-    bool m_breakpointsRestored;
 };
 
 } // namespace WebCore
index d1b8093..09d1258 100644 (file)
@@ -491,6 +491,11 @@ bool InspectorValue::asNumber(long*) const
     return false;
 }
 
+bool InspectorValue::asNumber(int*) const
+{
+    return false;
+}
+
 bool InspectorValue::asNumber(unsigned long*) const
 {
     return false;
@@ -581,6 +586,14 @@ bool InspectorBasicValue::asNumber(long* output) const
     return true;
 }
 
+bool InspectorBasicValue::asNumber(int* output) const
+{
+    if (type() != TypeNumber)
+        return false;
+    *output = static_cast<int>(m_doubleValue);
+    return true;
+}
+
 bool InspectorBasicValue::asNumber(unsigned long* output) const
 {
     if (type() != TypeNumber)
@@ -647,22 +660,6 @@ bool InspectorObject::getBoolean(const String& name, bool* output) const
     return value->asBoolean(output);
 }
 
-bool InspectorObject::getNumber(const String& name, long* output) const
-{
-    RefPtr<InspectorValue> value = get(name);
-    if (!value)
-        return false;
-    return value->asNumber(output);
-}
-
-bool InspectorObject::getNumber(const String& name, double* output) const
-{
-    RefPtr<InspectorValue> value = get(name);
-    if (!value)
-        return false;
-    return value->asNumber(output);
-}
-
 bool InspectorObject::getString(const String& name, String* output) const
 {
     RefPtr<InspectorValue> value = get(name);
@@ -695,6 +692,17 @@ PassRefPtr<InspectorValue> InspectorObject::get(const String& name) const
     return it->second;
 }
 
+void InspectorObject::remove(const String& name)
+{
+    m_data.remove(name);
+    for (size_t i = 0; i < m_order.size(); ++i) {
+        if (m_order[i] == name) {
+            m_order.remove(i);
+            break;
+        }
+    }
+}
+
 void InspectorObject::writeJSON(Vector<UChar>* output) const
 {
     output->append('{');
index 843f369..835c982 100644 (file)
@@ -72,6 +72,7 @@ public:
     virtual bool asBoolean(bool* output) const;
     virtual bool asNumber(double* output) const;
     virtual bool asNumber(long* output) const;
+    virtual bool asNumber(int* output) const;
     virtual bool asNumber(unsigned long* output) const;
     virtual bool asNumber(unsigned int* output) const;
     virtual bool asString(String* output) const;
@@ -114,6 +115,7 @@ public:
     virtual bool asBoolean(bool* output) const;
     virtual bool asNumber(double* output) const;
     virtual bool asNumber(long* output) const;
+    virtual bool asNumber(int* output) const;
     virtual bool asNumber(unsigned long* output) const;
     virtual bool asNumber(unsigned int* output) const;
 
@@ -178,15 +180,23 @@ public:
     void setObject(const String& name, PassRefPtr<InspectorObject>);
     void setArray(const String& name, PassRefPtr<InspectorArray>);
 
+    iterator find(const String& name);
     const_iterator find(const String& name) const;
     bool getBoolean(const String& name, bool* output) const;
-    bool getNumber(const String& name, long* output) const;
-    bool getNumber(const String& name, double* output) const;
+    template<class T> bool getNumber(const String& name, T* output) const
+    {
+        RefPtr<InspectorValue> value = get(name);
+        if (!value)
+            return false;
+        return value->asNumber(output);
+    }
     bool getString(const String& name, String* output) const;
     PassRefPtr<InspectorObject> getObject(const String& name) const;
     PassRefPtr<InspectorArray> getArray(const String& name) const;
     PassRefPtr<InspectorValue> get(const String& name) const;
 
+    void remove(const String& name);
+
     virtual void writeJSON(Vector<UChar>* output) const;
 
     iterator begin() { return m_data.begin(); }
@@ -228,6 +238,11 @@ private:
     Vector<RefPtr<InspectorValue> > m_data;
 };
 
+inline InspectorObject::iterator InspectorObject::find(const String& name)
+{
+    return m_data.find(name);
+}
+
 inline InspectorObject::const_iterator InspectorObject::find(const String& name) const
 {
     return m_data.find(name);
index 9521ccd..4917aef 100644 (file)
 namespace WebCore {
 
 struct ScriptBreakpoint {
-    ScriptBreakpoint(long lineNumber, long columnNumber, const String& condition, bool enabled)
+    ScriptBreakpoint()
+    {
+    }
+
+    ScriptBreakpoint(int lineNumber, int columnNumber, const String& condition, bool enabled)
         : lineNumber(lineNumber)
         , columnNumber(columnNumber)
         , condition(condition)
@@ -43,12 +47,8 @@ struct ScriptBreakpoint {
     {
     }
 
-    ScriptBreakpoint()
-    {
-    }
-
-    long lineNumber;
-    long columnNumber;
+    int lineNumber;
+    int columnNumber;
     String condition;
     bool enabled;
 };
index b8decf0..ebc6029 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.Breakpoint = function(debuggerModel, breakpointId, data)
+WebInspector.Breakpoint = function(id, url, sourceID, lineNumber, columnNumber, condition, enabled)
 {
-    this.id = breakpointId;
-    this.sourceID = data.sourceID;
-    this.line = data.lineNumber;
-    this.column = data.columnNumber;
-    this._condition = data.condition;
-    this._enabled = data.enabled;
-    this._debuggerModel = debuggerModel;
+    this.id = id;
+    this.url = url;
+    this.sourceID = sourceID;
+    this.lineNumber = lineNumber;
+    this.columnNumber = columnNumber;
+    this.condition = condition;
+    this.enabled = enabled;
+    this.locations = [];
 }
 
 WebInspector.Breakpoint.prototype = {
-    get enabled()
+    addLocation: function(sourceID, lineNumber, columnNumber)
     {
-        return this._enabled;
-    },
-
-    set enabled(enabled)
-    {
-        if (this._enabled === enabled)
-            return;
-        this.remove();
-        WebInspector.debuggerModel.setBreakpoint(this.sourceID, this.line, enabled, this.condition);
-    },
-
-    get condition()
-    {
-        return this._condition;
-    },
-
-    get url()
-    {
-        if (!this._url)
-            this._url = this._debuggerModel.scriptForSourceID(this.sourceID).sourceURL;
-        return this._url;
-    },
-
-    get data()
-    {
-        return { id: this.id, url: this.url, sourceID: this.sourceID, lineNumber: this.line, condition: this.condition };
-    },
-
-    remove: function()
-    {
-        this._debuggerModel.removeBreakpoint(this.id);
-        this.removeAllListeners();
-        delete this._debuggerModel;
+        this.locations.push({ sourceID: sourceID, lineNumber: lineNumber, columnNumber: columnNumber });
     }
 }
-
-WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype;
index 169b473..94345d5 100644 (file)
@@ -37,18 +37,14 @@ WebInspector.BreakpointManager = function()
 
     this._breakpoints = {};
     this._domBreakpointsRestored = false;
-    this._scriptBreakpoints = {};
 
     WebInspector.settings.addEventListener(WebInspector.Settings.Events.ProjectChanged, this._projectChanged, this);
-    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._scriptBreakpointAdded, this);
-    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._scriptBreakpointRemoved, this);
     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
 }
 
 WebInspector.BreakpointManager.BreakpointTypes = {
     DOM: "DOM",
-    JS: "JS",
     EventListener: "EventListener",
     XHR: "XHR"
 }
@@ -103,38 +99,6 @@ WebInspector.BreakpointManager.prototype = {
         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.EventListenerBreakpointAdded, breakpoint.view);
     },
 
-    _createJavaScriptBreakpoint: function(url, lineNumber, condition, enabled, restored)
-    {
-        var breakpointId = this._createJavaScriptBreakpointId(url, lineNumber);
-        if (breakpointId in this._breakpoints)
-            return;
-
-        var breakpoint = new WebInspector.JavaScriptBreakpoint(url, lineNumber, condition);
-        this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
-    },
-
-    _scriptBreakpointAdded: function(event)
-    {
-        var scriptBreakpoint = event.data;
-
-        if (!scriptBreakpoint.url)
-            return;
-
-        if (!scriptBreakpoint.restored)
-            this._createJavaScriptBreakpoint(scriptBreakpoint.url, scriptBreakpoint.originalLineNumber, scriptBreakpoint.condition, scriptBreakpoint.enabled, false);
-        var breakpointId = this._createJavaScriptBreakpointId(scriptBreakpoint.url, scriptBreakpoint.originalLineNumber);
-        this._scriptBreakpoints[scriptBreakpoint.id] = breakpointId;
-    },
-
-    _scriptBreakpointRemoved: function(event)
-    {
-        var scriptBreakpointId = event.data;
-        var breakpointId = this._scriptBreakpoints[scriptBreakpointId];
-        delete this._scriptBreakpoints[scriptBreakpointId];
-        if (breakpointId in this._breakpoints)
-            this._removeBreakpoint(breakpointId);
-    },
-
     createXHRBreakpoint: function(url)
     {
         this._createXHRBreakpoint(url, true, false);
@@ -231,7 +195,6 @@ WebInspector.BreakpointManager.prototype = {
     {
         this._breakpoints = {};
         this._domBreakpointsRestored = false;
-        this._scriptBreakpoints = {};
         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.ProjectChanged);
 
         var breakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || [];
@@ -239,14 +202,12 @@ WebInspector.BreakpointManager.prototype = {
             var breakpoint = breakpoints[i];
             if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.EventListener)
                 this._createEventListenerBreakpoint(breakpoint.condition.eventName, breakpoint.enabled, true);
-            else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.JS)
-                this._createJavaScriptBreakpoint(breakpoint.condition.url, breakpoint.condition.lineNumber, breakpoint.condition.condition, breakpoint.enabled, true);
             else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.XHR)
                 this._createXHRBreakpoint(breakpoint.condition.url, breakpoint.enabled, true);
         }
 
         if (!this._breakpointsPushedToFrontend) {
-            this._pushBreakpointsToBackend();
+            InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints);
             this._breakpointsPushedToFrontend = true;
         }
     },
@@ -307,34 +268,7 @@ WebInspector.BreakpointManager.prototype = {
         WebInspector.settings.nativeBreakpoints = breakpoints;
 
         this._stickyBreakpoints[WebInspector.settings.projectId] = breakpoints;
-        this._pushBreakpointsToBackend();
-    },
-
-    _pushBreakpointsToBackend: function()
-    {
-        var allJavaScriptBreakpoints = {};
-        var allBrowserBreakpoints = {};
-        for (var projectId in this._stickyBreakpoints) {
-            var breakpoints = this._stickyBreakpoints[projectId];
-            var javaScriptBreakpoints = [];
-            var browserBreakpoints = [];
-            for (var i = 0; i < breakpoints.length; ++i) {
-                if (breakpoints[i].type == WebInspector.BreakpointManager.BreakpointTypes.JS) {
-                    var data = {};
-                    data.enabled = breakpoints[i].enabled;
-                    for (var p in breakpoints[i].condition)
-                        data[p] = breakpoints[i].condition[p];
-                    javaScriptBreakpoints.push(data);
-                } else
-                    browserBreakpoints.push(breakpoints[i]);
-            }
-            if (javaScriptBreakpoints.length)
-                allJavaScriptBreakpoints[projectId] = javaScriptBreakpoints;
-            if (browserBreakpoints.length)
-                allBrowserBreakpoints[projectId] = browserBreakpoints;
-        }
-        InspectorBackend.setAllJavaScriptBreakpoints(allJavaScriptBreakpoints);
-        InspectorBackend.setAllBrowserBreakpoints(allBrowserBreakpoints);
+        InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints);
     },
 
     _validateBreakpoints: function(persistentBreakpoints)
@@ -355,15 +289,12 @@ WebInspector.BreakpointManager.prototype = {
                 if (typeof condition.eventName !== "string")
                     continue;
                 id += condition.eventName;
-            } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.JS) {
-                if (typeof condition.url !== "string" || typeof condition.lineNumber !== "number" || typeof condition.condition !== "string")
-                    continue;
-                id += condition.url + ":" + condition.lineNumber;
             } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.XHR) {
                 if (typeof condition.url !== "string")
                     continue;
                 id += condition.url;
-            }
+            } else
+                continue;
             if (id in breakpointsSet)
                 continue;
             breakpointsSet[id] = true;
@@ -377,11 +308,6 @@ WebInspector.BreakpointManager.prototype = {
         return "dom:" + nodeId + ":" + type;
     },
 
-    _createJavaScriptBreakpointId: function(url, lineNumber)
-    {
-        return "js:" + url + ":" + lineNumber;
-    },
-
     _createEventListenerBreakpointId: function(eventName)
     {
         return "eventListner:" + eventName;
@@ -420,29 +346,6 @@ WebInspector.DOMBreakpoint.prototype = {
     }
 }
 
-WebInspector.JavaScriptBreakpoint = function(url, lineNumber, condition)
-{
-    this._url = url;
-    this._lineNumber = lineNumber;
-    this._condition = condition;
-}
-
-WebInspector.JavaScriptBreakpoint.prototype = {
-    _enable: function()
-    {
-    },
-
-    _disable: function()
-    {
-    },
-
-    _serializeToJSON: function()
-    {
-        var type = WebInspector.BreakpointManager.BreakpointTypes.JS;
-        return { type: type, condition: { url: this._url, lineNumber: this._lineNumber, columnNumber: 1, condition: this._condition } };
-    }
-}
-
 WebInspector.EventListenerBreakpoint = function(eventName)
 {
     this._eventName = eventName;
index b237ca2..d8e53dd 100644 (file)
@@ -40,6 +40,8 @@ WebInspector.JavaScriptBreakpointsSidebarPane = function(title)
 
     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this);
     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this);
+    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this);
+    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
     WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
     WebInspector.breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.ProjectChanged, this._projectChanged, this);
@@ -50,7 +52,9 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
     {
         var breakpoint = event.data;
         var breakpointId = breakpoint.id;
-        var data = breakpoint.data;
+
+        if (breakpoint.url && !WebInspector.debuggerModel.scriptsForURL(breakpoint.url).length)
+            return;
 
         var element = document.createElement("li");
 
@@ -64,7 +68,7 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
         var label = document.createElement("span");
         element.appendChild(label);
 
-        element._data = data;
+        element._data = breakpoint;
         var currentElement = this.listElement.firstChild;
         while (currentElement) {
             if (currentElement._data && this._compareBreakpoints(currentElement._data, element._data) > 0)
@@ -75,10 +79,9 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
 
         element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this, breakpointId), true);
 
-        this._setupBreakpointElement(data, element);
+        this._setupBreakpointElement(breakpoint, element);
 
         var breakpointItem = {};
-        breakpointItem.data = data;
         breakpointItem.element = element;
         breakpointItem.checkbox = checkbox;
         this._items[breakpointId] = breakpointItem;
@@ -97,6 +100,23 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
         }
     },
 
+    _breakpointResolved: function(event)
+    {
+        var breakpoint = event.data;
+        this._breakpointRemoved({ data: breakpoint.id });
+        this._breakpointAdded({ data: breakpoint });
+    },
+
+    _parsedScriptSource: function(event)
+    {
+        var url = event.data.sourceURL;
+        var breakpoints = WebInspector.debuggerModel.breakpoints;
+        for (var id in breakpoints) {
+            if (!(id in this._items))
+                this._breakpointAdded({ data: breakpoints[id] });
+        }
+    },
+
     _breakpointEnableChanged: function(enabled, event)
     {
         var breakpointId = event.data;
@@ -107,7 +127,8 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
 
     _breakpointItemCheckboxClicked: function(breakpointId, event)
     {
-        this._setBreakpointEnabled(breakpointId, event.target.checked);
+        var breakpoint = WebInspector.debuggerModel.breakpointForId(breakpointId);
+        WebInspector.debuggerModel.updateBreakpoint(breakpointId, breakpoint.condition, event.target.checked);
 
         // Breakpoint element may have it's own click handler.
         event.stopPropagation();
@@ -186,23 +207,32 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
 
     _setupBreakpointElement: function(data, element)
     {
+        var sourceID;
+        var lineNumber = data.lineNumber;
+        if (data.locations.length) {
+            sourceID = data.locations[0].sourceID;
+            lineNumber = data.locations[0].lineNumber;
+        }
+
         var displayName = data.url ? WebInspector.displayNameForURL(data.url) : WebInspector.UIString("(program)");
-        var labelElement = document.createTextNode(displayName + ":" + data.lineNumber);
+        var labelElement = document.createTextNode(displayName + ":" + (lineNumber + 1));
         element.appendChild(labelElement);
 
         var sourceTextElement = document.createElement("div");
         sourceTextElement.className = "source-text monospace";
         element.appendChild(sourceTextElement);
 
-        function didGetSourceLine(text)
-        {
-            sourceTextElement.textContent = text;
+        if (sourceID) {
+            function didGetSourceLine(text)
+            {
+                sourceTextElement.textContent = text;
+            }
+            var script = WebInspector.debuggerModel.scriptForSourceID(sourceID);
+            script.sourceLine(lineNumber, didGetSourceLine.bind(this));
         }
-        var script = WebInspector.debuggerModel.scriptForSourceID(data.sourceID);
-        script.sourceLine(data.lineNumber, didGetSourceLine.bind(this));
 
         element.addStyleClass("cursor-pointer");
-        var clickHandler = WebInspector.panels.scripts.showSourceLine.bind(WebInspector.panels.scripts, data.url, data.lineNumber);
+        var clickHandler = WebInspector.panels.scripts.showSourceLine.bind(WebInspector.panels.scripts, data.url, data.lineNumber + 1);
         element.addEventListener("click", clickHandler, false);
     },
 
@@ -214,13 +244,6 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
             return breakpoint.id;
    },
 
-    _setBreakpointEnabled: function(breakpointId, enabled)
-    {
-        var breakpoint = WebInspector.debuggerModel.breakpointForId(breakpointId);
-        WebInspector.debuggerModel.removeBreakpoint(breakpointId);
-        WebInspector.debuggerModel.setBreakpoint(breakpoint.sourceID, breakpoint.line, enabled, breakpoint.condition);
-    },
-
     _removeBreakpoint: function(breakpointId)
     {
         WebInspector.debuggerModel.removeBreakpoint(breakpointId);
index 32d28e7..1bf1e47 100644 (file)
@@ -33,7 +33,6 @@ WebInspector.DebuggerModel = function()
     this._paused = false;
     this._callFrames = [];
     this._breakpoints = {};
-    this._sourceIDAndLineToBreakpointId = {};
     this._scripts = {};
 
     InspectorBackend.registerDomainDispatcher("Debugger", new WebInspector.DebuggerDispatcher(this));
@@ -46,70 +45,116 @@ WebInspector.DebuggerModel.Events = {
     FailedToParseScriptSource: "failed-to-parse-script-source",
     ScriptSourceChanged: "script-source-changed",
     BreakpointAdded: "breakpoint-added",
-    BreakpointRemoved: "breakpoint-removed"
+    BreakpointRemoved: "breakpoint-removed",
+    BreakpointResolved: "breakpoint-resolved"
 }
 
 WebInspector.DebuggerModel.prototype = {
+    enableDebugger: function()
+    {
+        InspectorBackend.enableDebugger();
+        if (this._breakpointsPushedToBackend)
+            return;
+        var breakpoints = WebInspector.settings.breakpoints;
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            if (typeof breakpoint.url !== "string" || typeof breakpoint.lineNumber !== "number" || typeof breakpoint.columnNumber !== "number" ||
+                typeof breakpoint.condition !== "string" || typeof breakpoint.enabled !== "boolean")
+                continue;
+            this.setBreakpoint(breakpoint.url, breakpoint.lineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled);
+        }
+        this._breakpointsPushedToBackend = true;
+    },
+
+    disableDebugger: function()
+    {
+        InspectorBackend.disableDebugger();
+    },
+
     continueToLine: function(sourceID, lineNumber)
     {
-        function didSetBreakpoint(breakpointId, actualLineNumber)
+        InspectorBackend.continueToLocation(sourceID, lineNumber, 0);
+    },
+
+    setBreakpoint: function(url, lineNumber, columnNumber, condition, enabled)
+    {
+        function didSetBreakpoint(breakpointsPushedToBackend, breakpointId, locations)
         {
             if (!breakpointId)
                 return;
-            if (this.findBreakpoint(sourceID, actualLineNumber)) {
-                InspectorBackend.removeBreakpoint(breakpointId);
-                return;
-            }
-            if ("_continueToLineBreakpointId" in this)
-                InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId);
-            this._continueToLineBreakpointId = breakpointId;
+            var breakpoint = new WebInspector.Breakpoint(breakpointId, url, "", lineNumber, columnNumber, condition, enabled);
+            breakpoint.locations = locations;
+            this._breakpoints[breakpointId] = breakpoint;
+            if (breakpointsPushedToBackend)
+                this._saveBreakpoints();
+            this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint);
         }
-        var breakpoint = { sourceID: sourceID, lineNumber: lineNumber, columnNumber: 1, condition: "", enabled: true };
-        InspectorBackend.setBreakpoint(breakpoint, didSetBreakpoint.bind(this));
-        if (this._paused)
-            InspectorBackend.resume();
+        InspectorBackend.setJavaScriptBreakpoint(url, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this, this._breakpointsPushedToBackend));
     },
 
-    setBreakpoint: function(sourceID, lineNumber, enabled, condition)
+    setBreakpointBySourceId: function(sourceID, lineNumber, columnNumber, condition, enabled)
     {
         function didSetBreakpoint(breakpointId, actualLineNumber, actualColumnNumber)
         {
             if (!breakpointId)
                 return;
-            breakpoint.originalLineNumber = breakpoint.lineNumber;
-            breakpoint.originalColumnumber = breakpoint.columnNumber;
-            breakpoint.lineNumber = actualLineNumber;
-            breakpoint.columnNumber = actualColumnNumber;
-            this._breakpointSetOnBackend(breakpointId, breakpoint, false);
+            var breakpoint = new WebInspector.Breakpoint(breakpointId, "", sourceID, lineNumber, columnNumber, condition, enabled);
+            breakpoint.addLocation(sourceID, actualLineNumber, actualColumnNumber);
+            this._breakpoints[breakpointId] = breakpoint;
+            this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint);
         }
-        var breakpoint = { sourceID: sourceID, lineNumber: lineNumber, columnNumber: 1, condition: condition, enabled: enabled };
-        InspectorBackend.setBreakpoint(breakpoint, didSetBreakpoint.bind(this));
+        InspectorBackend.setJavaScriptBreakpointBySourceId(sourceID, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this));
     },
 
     removeBreakpoint: function(breakpointId)
     {
-        InspectorBackend.removeBreakpoint(breakpointId);
+        InspectorBackend.removeJavaScriptBreakpoint(breakpointId);
         var breakpoint = this._breakpoints[breakpointId];
         delete this._breakpoints[breakpointId];
-        delete this._sourceIDAndLineToBreakpointId[this._encodeSourceIDAndLine(breakpoint.sourceID, breakpoint.line)];
+        this._saveBreakpoints();
         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointRemoved, breakpointId);
-        breakpoint.dispatchEventToListeners("removed");
     },
 
-    _breakpointSetOnBackend: function(breakpointId, breakpointData, restored)
+    updateBreakpoint: function(breakpointId, condition, enabled)
+    {
+        var breakpoint = this._breakpoints[breakpointId];
+        this.removeBreakpoint(breakpointId);
+        if (breakpoint.url)
+            this.setBreakpoint(breakpoint.url, breakpoint.lineNumber, breakpoint.columnNumber, condition, enabled);
+        else
+            this.setBreakpointBySourceId(breakpoint.sourceID, breakpoint.lineNumber, breakpoint.columnNumber, condition, enabled);
+    },
+
+    _breakpointResolved: function(breakpointId, sourceID, lineNumber, columnNumber)
     {
-        var sourceIDAndLine = this._encodeSourceIDAndLine(breakpointData.sourceID, breakpointData.lineNumber);
-        if (sourceIDAndLine in this._sourceIDAndLineToBreakpointId) {
-            InspectorBackend.removeBreakpoint(breakpointId);
+        var breakpoint = this._breakpoints[breakpointId];
+        if (!breakpoint)
             return;
+        breakpoint.addLocation(sourceID, lineNumber, columnNumber);
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, breakpoint);
+    },
+
+    _saveBreakpoints: function()
+    {
+        var serializedBreakpoints = [];
+        for (var id in this._breakpoints) {
+            var breakpoint = this._breakpoints[id];
+            if (!breakpoint.url)
+                continue;
+            var serializedBreakpoint = {};
+            serializedBreakpoint.url = breakpoint.url;
+            serializedBreakpoint.lineNumber = breakpoint.lineNumber;
+            serializedBreakpoint.columnNumber = breakpoint.columnNumber;
+            serializedBreakpoint.condition = breakpoint.condition;
+            serializedBreakpoint.enabled = breakpoint.enabled;
+            serializedBreakpoints.push(serializedBreakpoint);
         }
+        WebInspector.settings.breakpoints = serializedBreakpoints;
+    },
 
-        var breakpoint = new WebInspector.Breakpoint(this, breakpointId, breakpointData);
-        breakpoint.restored = restored;
-        breakpoint.originalLineNumber = breakpointData.originalLineNumber;
-        this._breakpoints[breakpointId] = breakpoint;
-        this._sourceIDAndLineToBreakpointId[sourceIDAndLine] = breakpointId;
-        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint);
+    get breakpoints()
+    {
+        return this._breakpoints;
     },
 
     breakpointForId: function(breakpointId)
@@ -130,23 +175,26 @@ WebInspector.DebuggerModel.prototype = {
 
     findBreakpoint: function(sourceID, lineNumber)
     {
-        var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber);
-        var breakpointId = this._sourceIDAndLineToBreakpointId[sourceIDAndLine];
-        return this._breakpoints[breakpointId];
-    },
-
-    _encodeSourceIDAndLine: function(sourceID, lineNumber)
-    {
-        return sourceID + ":" + lineNumber;
+        for (var id in this._breakpoints) {
+            var locations = this._breakpoints[id].locations;
+            for (var i = 0; i < locations.length; ++i) {
+                if (locations[i].sourceID == sourceID && locations[i].lineNumber + 1 === lineNumber)
+                    return this._breakpoints[id];
+            }
+        }
     },
 
     reset: function()
     {
         this._paused = false;
         this._callFrames = [];
-        this._breakpoints = {};
-        delete this._oneTimeBreakpoint;
-        this._sourceIDAndLineToBreakpointId = {};
+        for (var id in this._breakpoints) {
+            var breakpoint = this._breakpoints[id];
+            if (!breakpoint.url)
+                this.removeBreakpoint(id);
+            else
+                breakpoint.locations = [];
+        }
         this._scripts = {};
     },
 
@@ -195,10 +243,15 @@ WebInspector.DebuggerModel.prototype = {
         var diff = Array.diff(oldSource.split("\n"), script.source.split("\n"));
         for (var id in this._breakpoints) {
             var breakpoint = this._breakpoints[id];
-            if (breakpoint.sourceID !== sourceID)
-                continue;
-            breakpoint.remove();
-            var lineNumber = breakpoint.line - 1;
+            if (breakpoint.url) {
+                if (breakpoint.url !== script.sourceURL)
+                    continue;
+            } else {
+                if (breakpoint.sourceID !== sourceID)
+                    continue;
+            }
+            this.removeBreakpoint(breakpoint.id);
+            var lineNumber = breakpoint.lineNumber;
             var newLineNumber = diff.left[lineNumber].row;
             if (newLineNumber === undefined) {
                 for (var i = lineNumber - 1; i >= 0; --i) {
@@ -213,8 +266,12 @@ WebInspector.DebuggerModel.prototype = {
                     break;
                 }
             }
-            if (newLineNumber !== undefined)
-                this.setBreakpoint(sourceID, newLineNumber + 1, breakpoint.enabled, breakpoint.condition);
+            if (newLineNumber === undefined)
+                continue;
+            if (breakpoint.url)
+                this.setBreakpoint(breakpoint.url, newLineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled);
+            else
+                this.setBreakpointBySourceId(sourceID, newLineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled);
         }
 
         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ScriptSourceChanged, { sourceID: sourceID, oldSource: oldSource });
@@ -229,10 +286,6 @@ WebInspector.DebuggerModel.prototype = {
     {
         this._paused = true;
         this._callFrames = details.callFrames;
-        if ("_continueToLineBreakpointId" in this) {
-            InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId);
-            delete this._continueToLineBreakpointId;
-        }
         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details);
     },
 
@@ -301,9 +354,9 @@ WebInspector.DebuggerDispatcher.prototype = {
         this._debuggerModel._failedToParseScriptSource(sourceURL, source, startingLine, errorLine, errorMessage);
     },
 
-    breakpointResolved: function(breakpointId, breakpoint)
+    breakpointResolved: function(breakpointId, sourceID, lineNumber, columnNumber)
     {
-        this._debuggerModel._breakpointSetOnBackend(breakpointId, breakpoint, true);
+        this._debuggerModel._breakpointResolved(breakpointId, sourceID, lineNumber, columnNumber);
     },
 
     didCreateWorker: function()
index 6e3b18d..8d3eabf 100644 (file)
@@ -78,7 +78,7 @@ WebInspector.Script.prototype = {
     {
         function extractSourceLine()
         {
-            lineNumber -= this.startingLine;
+            lineNumber -= this.lineOffset;
             callback(this._source.substring(this._lineEndings[lineNumber - 1], this._lineEndings[lineNumber]));
         }
 
index ddc906a..75c6841 100644 (file)
@@ -803,10 +803,10 @@ WebInspector.ScriptsPanel.prototype = {
 
         if (this._debuggerEnabled) {
             WebInspector.settings.debuggerEnabled = false;
-            InspectorBackend.disableDebugger();
+            WebInspector.debuggerModel.disableDebugger();
         } else {
             WebInspector.settings.debuggerEnabled = !!optionalAlways;
-            InspectorBackend.enableDebugger();
+            WebInspector.debuggerModel.enableDebugger();
         }
     },
 
index 1cea5e1..83ebaf0 100644 (file)
@@ -71,8 +71,8 @@ WebInspector.Settings = function()
     this.installApplicationSetting("showInheritedComputedStyleProperties", false);
     this.installApplicationSetting("showUserAgentStyles", true);
     this.installApplicationSetting("watchExpressions", []);
+    this.installApplicationSetting("breakpoints", []);
 
-    this.installProjectSetting("breakpoints", {});
     this.installProjectSetting("nativeBreakpoints", []);
 }
 
index 248de5a..d9c5ac6 100644 (file)
@@ -208,6 +208,8 @@ WebInspector.SourceFrame.prototype = {
         this._textViewer.endUpdates();
 
         WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this);
+        WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this);
+        WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this);
     },
 
     _setTextViewerDecorations: function()
@@ -223,15 +225,29 @@ WebInspector.SourceFrame.prototype = {
         if (this._executionLine)
             this.setExecutionLine(this._executionLine);
 
-        var breakpoints = this._breakpoints();
-        for (var i = 0; i < breakpoints.length; ++i)
-            this._addBreakpoint(breakpoints[i]);
+        this._breakpointIdToTextViewerLineNumber = {};
+        this._textViewerLineNumberToBreakpointId = {};
+        var breakpoints = WebInspector.debuggerModel.breakpoints;
+        for (var id in breakpoints)
+            this._breakpointAdded({ data: breakpoints[id] });
 
         this._textViewer.resize();
 
         this._textViewer.endUpdates();
     },
 
+    _shouldDisplayBreakpoint: function(breakpoint)
+    {
+        if (this._url)
+            return this._url === breakpoint.url;
+        var scripts = this._contentProvider.scripts();
+        for (var i = 0; i < scripts.length; ++i) {
+            if (breakpoint.sourceID === scripts[i].sourceID)
+                return true;
+        }
+        return false;
+    },
+
     performSearch: function(query, callback)
     {
         // Call searchCanceled since it will reset everything we need before doing a new search.
@@ -455,54 +471,57 @@ WebInspector.SourceFrame.prototype = {
     {
         var breakpoint = event.data;
 
-        if (breakpoint.sourceID in this._sourceIDSet())
-            this._addBreakpoint(breakpoint);
-    },
+        if (!this._shouldDisplayBreakpoint(breakpoint))
+            return;
 
-    _addBreakpoint: function(breakpoint)
-    {
-        var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1);
+        var resolved = breakpoint.locations.length;
+        var breakpointLineNumber = breakpoint.lineNumber;
+        if (resolved)
+            breakpointLineNumber = breakpoint.locations[0].lineNumber;
+
+        var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpointLineNumber);
         if (textViewerLineNumber >= this._textModel.linesCount)
             return;
 
-        breakpoint.addEventListener("enable-changed", this._breakpointChanged, this);
-        breakpoint.addEventListener("condition-changed", this._breakpointChanged, this);
-        breakpoint.addEventListener("removed", this._breakpointRemoved, this);
+        var existingBreakpointId = this._textViewerLineNumberToBreakpointId[textViewerLineNumber];
+        if (existingBreakpointId) {
+            WebInspector.debuggerModel.removeBreakpoint(breakpoint.id);
+            return;
+        }
 
-        this._setBreakpointDecoration(textViewerLineNumber, breakpoint.enabled, !!breakpoint.condition);
+        this._breakpointIdToTextViewerLineNumber[breakpoint.id] = textViewerLineNumber;
+        this._textViewerLineNumberToBreakpointId[textViewerLineNumber] = breakpoint.id;
+        this._setBreakpointDecoration(textViewerLineNumber, resolved, breakpoint.enabled, !!breakpoint.condition);
     },
 
     _breakpointRemoved: function(event)
     {
-        var breakpoint = event.target;
+        var breakpointId = event.data;
 
-        breakpoint.removeEventListener("enable-changed", null, this);
-        breakpoint.removeEventListener("condition-changed", null, this);
-        breakpoint.removeEventListener("removed", null, this);
+        var textViewerLineNumber = this._breakpointIdToTextViewerLineNumber[breakpointId];
+        if (textViewerLineNumber === undefined)
+            return;
 
-        var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1);
+        delete this._breakpointIdToTextViewerLineNumber[breakpointId];
+        delete this._textViewerLineNumberToBreakpointId[textViewerLineNumber];
         this._removeBreakpointDecoration(textViewerLineNumber);
     },
 
-    _breakpointChanged: function(event)
+    _breakpointResolved: function(event)
     {
-        var breakpoint = event.target;
-        var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1);
-        this._setBreakpointDecoration(textViewerLineNumber, breakpoint.enabled, !!breakpoint.condition);
+        var breakpoint = event.data;
+        this._breakpointRemoved({ data: breakpoint.id });
+        this._breakpointAdded({ data: breakpoint });
     },
 
-    _setBreakpointDecoration: function(lineNumber, enabled, hasCondition)
+    _setBreakpointDecoration: function(lineNumber, resolved, enabled, hasCondition)
     {
         this._textViewer.beginUpdates();
         this._textViewer.addDecoration(lineNumber, "webkit-breakpoint");
-        if (enabled)
-            this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
-        else
+        if (!enabled)
             this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
         if (hasCondition)
             this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
-        else
-            this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
         this._textViewer.endUpdates();
     },
 
@@ -530,14 +549,14 @@ WebInspector.SourceFrame.prototype = {
 
         contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToLine.bind(this, originalLineNumber));
 
-        var breakpoint = this._findBreakpoint(originalLineNumber);
+        var breakpoint = this._findBreakpoint(textViewerLineNumber);
         if (!breakpoint) {
             // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint.
             contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, originalLineNumber, "", true));
 
             function addConditionalBreakpoint()
             {
-                this._setBreakpointDecoration(textViewerLineNumber, true, true);
+                this._setBreakpointDecoration(textViewerLineNumber, true, true, true);
                 function didEditBreakpointCondition(committed, condition)
                 {
                     this._removeBreakpointDecoration(textViewerLineNumber);
@@ -549,23 +568,24 @@ WebInspector.SourceFrame.prototype = {
             contextMenu.appendItem(WebInspector.UIString("Add Conditional Breakpoint…"), addConditionalBreakpoint.bind(this));
         } else {
             // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable.
-            contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), breakpoint.remove.bind(breakpoint));
+            function removeBreakpoint()
+            {
+                WebInspector.debuggerModel.removeBreakpoint(breakpoint.id);
+            }
+            contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), removeBreakpoint);
             function editBreakpointCondition()
             {
                 function didEditBreakpointCondition(committed, condition)
                 {
-                    if (committed) {
-                        breakpoint.remove();
-                        this._setBreakpoint(originalLineNumber, breakpoint.enabled, condition);
-                    }
+                    if (committed)
+                        WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, condition, breakpoint.enabled);
                 }
                 this._editBreakpointCondition(textViewerLineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this));
             }
             contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpointCondition.bind(this));
             function setBreakpointEnabled(enabled)
             {
-                breakpoint.remove();
-                this._setBreakpoint(originalLineNumber, enabled, breakpoint.condition);
+                WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, breakpoint.condition, enabled);
             }
             if (breakpoint.enabled)
                 contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), setBreakpointEnabled.bind(this, false));
@@ -589,13 +609,15 @@ WebInspector.SourceFrame.prototype = {
         var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number");
         if (!target)
             return;
-        var originalLineNumber = this._formatter.formattedLineNumberToOriginalLineNumber(target.lineNumber);
+        var textViewerLineNumber = target.lineNumber;
+        var originalLineNumber = this._formatter.formattedLineNumberToOriginalLineNumber(textViewerLineNumber);
 
-        var breakpoint = this._findBreakpoint(originalLineNumber);
+        var breakpoint = this._findBreakpoint(textViewerLineNumber);
         if (breakpoint) {
-            breakpoint.remove();
             if (event.shiftKey)
-                this._setBreakpoint(originalLineNumber, !breakpoint.enabled, breakpoint.condition);
+                WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, breakpoint.condition, !breakpoint.enabled);
+            else
+                WebInspector.debuggerModel.removeBreakpoint(breakpoint.id);
         } else
             this._setBreakpoint(originalLineNumber, true, "");
         event.preventDefault();
@@ -844,7 +866,7 @@ WebInspector.SourceFrame.prototype = {
         var sourceID = this._sourceIDForLine(lineNumber);
         if (!sourceID)
             return;
-        WebInspector.debuggerModel.continueToLine(sourceID, lineNumber + 1);
+        WebInspector.debuggerModel.continueToLine(sourceID, lineNumber);
     },
 
     _doubleClick: function(event)
@@ -878,24 +900,22 @@ WebInspector.SourceFrame.prototype = {
 
     _setBreakpoint: function(lineNumber, enabled, condition)
     {
-        var sourceID = this._sourceIDForLine(lineNumber);
-        if (!sourceID)
-            return;
-        WebInspector.debuggerModel.setBreakpoint(sourceID, lineNumber + 1, enabled, condition);
+        if (this._url)
+            WebInspector.debuggerModel.setBreakpoint(this._url, lineNumber, 0, condition, enabled);
+        else {
+            var sourceID = this._sourceIDForLine(lineNumber);
+            if (!sourceID)
+                return;
+            WebInspector.debuggerModel.setBreakpointBySourceId(sourceID, lineNumber, 0, condition, enabled);
+        }
         if (!WebInspector.panels.scripts.breakpointsActivated)
             WebInspector.panels.scripts.toggleBreakpointsClicked();
     },
 
-    _breakpoints: function()
+    _findBreakpoint: function(textViewerLineNumber)
     {
-        var sourceIDSet = this._sourceIDSet();
-        return WebInspector.debuggerModel.queryBreakpoints(function(b) { return b.sourceID in sourceIDSet; });
-    },
-
-    _findBreakpoint: function(lineNumber)
-    {
-        var sourceID = this._sourceIDForLine(lineNumber);
-        return WebInspector.debuggerModel.findBreakpoint(sourceID, lineNumber + 1);
+        var breakpointId = this._textViewerLineNumberToBreakpointId[textViewerLineNumber];
+        return WebInspector.debuggerModel.breakpointForId(breakpointId);
     },
 
     _sourceIDForLine: function(lineNumber)
@@ -911,15 +931,6 @@ WebInspector.SourceFrame.prototype = {
             }
         }
         return sourceIDForLine;
-    },
-
-    _sourceIDSet: function()
-    {
-        var scripts = this._contentProvider.scripts();
-        var sourceIDSet = {};
-        for (var i = 0; i < scripts.length; ++i)
-            sourceIDSet[scripts[i].sourceID] = true;
-        return sourceIDSet;
     }
 }
 
index 1472fe5..81946ce 100644 (file)
@@ -609,7 +609,7 @@ WebInspector.doLoadedDone = function()
     InspectorBackend.populateScriptObjects(onPopulateScriptObjects);
 
     if (Preferences.debuggerAlwaysEnabled || WebInspector.settings.debuggerEnabled)
-        InspectorBackend.enableDebugger();
+        this.debuggerModel.enableDebugger();
     if (Preferences.profilerAlwaysEnabled || WebInspector.settings.profilerEnabled)
         InspectorBackend.enableProfiler();
     if (WebInspector.settings.monitoringXHREnabled)
index 5bb1383..ef51e16 100644 (file)
@@ -1,3 +1,13 @@
+2011-02-01  Pavel Podivilov  <podivilov@chromium.org>
+
+        Reviewed by Pavel Feldman.
+
+        Web Inspector: introduce new api for managing JavaScript breakpoints.
+        https://bugs.webkit.org/show_bug.cgi?id=53235
+
+        * src/WebDevToolsAgentImpl.cpp:
+        (WebKit::WebDevToolsAgent::shouldInterruptForMessage):
+
 2011-02-02  Evan Martin  <evan@chromium.org>
 
         Unreviewed, DEPS change.
index 005dfaf..cf89640 100644 (file)
@@ -407,8 +407,8 @@ bool WebDevToolsAgent::shouldInterruptForMessage(const WebString& message)
     if (!InspectorBackendDispatcher::getCommandName(message, &commandName))
         return false;
     return commandName == InspectorBackendDispatcher::pauseCmd
-        || commandName == InspectorBackendDispatcher::setBreakpointCmd
-        || commandName == InspectorBackendDispatcher::removeBreakpointCmd
+        || commandName == InspectorBackendDispatcher::setJavaScriptBreakpointCmd
+        || commandName == InspectorBackendDispatcher::removeJavaScriptBreakpointCmd
         || commandName == InspectorBackendDispatcher::activateBreakpointsCmd
         || commandName == InspectorBackendDispatcher::deactivateBreakpointsCmd
         || commandName == InspectorBackendDispatcher::startProfilingCmd