2010-12-21 Pavel Podivilov <podivilov@chromium.org>
authorpodivilov@chromium.org <podivilov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Dec 2010 13:13:28 +0000 (13:13 +0000)
committerpodivilov@chromium.org <podivilov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Dec 2010 13:13:28 +0000 (13:13 +0000)
        Reviewed by Yury Semikhatsky.

        Web Inspector: persist JavaScript breakpoints in frontend settings.
        https://bugs.webkit.org/show_bug.cgi?id=48434

        * http/tests/inspector/debugger-test2.js:
        (initialize_DebuggerTest.InspectorTest.setBreakpoint):
        * inspector/debugger-breakpoints-not-activated-on-reload.html:
        * inspector/debugger-pause-on-breakpoint.html:
        * inspector/report-protocol-errors-expected.txt:
        * inspector/report-protocol-errors.html:
2010-12-21  Pavel Podivilov  <podivilov@chromium.org>

        Reviewed by Yury Semikhatsky.

        Web Inspector: persist JavaScript breakpoints in frontend settings.
        https://bugs.webkit.org/show_bug.cgi?id=48434

        * 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):
        (WebCore::ScriptDebugServer::removeBreakpoint):
        * bindings/v8/ScriptDebugServer.h:
        * inspector/Inspector.idl:
        * inspector/InspectorBackend.cpp:
        * inspector/InspectorController.cpp:
        (WebCore::InspectorController::InspectorController):
        (WebCore::InspectorController::enableDebuggerFromFrontend):
        (WebCore::InspectorController::setStickyBreakpoints):
        (WebCore::InspectorController::restoreStickyBreakpoint):
        * inspector/InspectorController.h:
        * inspector/InspectorDebuggerAgent.cpp:
        (WebCore::InspectorDebuggerAgent::InspectorDebuggerAgent):
        (WebCore::InspectorDebuggerAgent::setStickyBreakpoint):
        (WebCore::InspectorDebuggerAgent::setBreakpoint):
        (WebCore::InspectorDebuggerAgent::removeBreakpoint):
        (WebCore::InspectorDebuggerAgent::restoreBreakpoint):
        (WebCore::InspectorDebuggerAgent::clearForPageNavigation):
        (WebCore::InspectorDebuggerAgent::didParseSource):
        * inspector/InspectorDebuggerAgent.h:
        * inspector/front-end/Breakpoint.js:
        (WebInspector.Breakpoint):
        (WebInspector.Breakpoint.prototype.remove):
        * inspector/front-end/BreakpointManager.js:
        (WebInspector.BreakpointManager):
        (WebInspector.DOMBreakpoint.prototype._serializeToJSON):
        (WebInspector.JavaScriptBreakpoint):
        (WebInspector.XHRBreakpoint.prototype._serializeToJSON):
        * inspector/front-end/DebuggerModel.js:
        (WebInspector.DebuggerModel):
        * inspector/front-end/ScriptsPanel.js:
        (WebInspector.ScriptsPanel.prototype._debuggerPaused):
        * inspector/front-end/SourceFrame.js:

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/inspector/debugger-test2.js
LayoutTests/inspector/debugger-breakpoints-not-activated-on-reload.html
LayoutTests/inspector/debugger-pause-on-breakpoint.html
LayoutTests/inspector/report-protocol-errors-expected.txt
LayoutTests/inspector/report-protocol-errors.html
WebCore/ChangeLog
WebCore/bindings/js/ScriptDebugServer.cpp
WebCore/bindings/js/ScriptDebugServer.h
WebCore/bindings/v8/DebuggerScript.js
WebCore/bindings/v8/ScriptDebugServer.cpp
WebCore/bindings/v8/ScriptDebugServer.h
WebCore/inspector/Inspector.idl
WebCore/inspector/InspectorBackend.cpp
WebCore/inspector/InspectorController.cpp
WebCore/inspector/InspectorController.h
WebCore/inspector/InspectorDebuggerAgent.cpp
WebCore/inspector/InspectorDebuggerAgent.h
WebCore/inspector/front-end/Breakpoint.js
WebCore/inspector/front-end/BreakpointManager.js
WebCore/inspector/front-end/DebuggerModel.js
WebCore/inspector/front-end/ScriptsPanel.js
WebCore/inspector/front-end/SourceFrame.js

index 58f3536..8200abd 100644 (file)
@@ -1,3 +1,17 @@
+2010-12-21  Pavel Podivilov  <podivilov@chromium.org>
+
+        Reviewed by Yury Semikhatsky.
+
+        Web Inspector: persist JavaScript breakpoints in frontend settings.
+        https://bugs.webkit.org/show_bug.cgi?id=48434
+
+        * http/tests/inspector/debugger-test2.js:
+        (initialize_DebuggerTest.InspectorTest.setBreakpoint):
+        * inspector/debugger-breakpoints-not-activated-on-reload.html:
+        * inspector/debugger-pause-on-breakpoint.html:
+        * inspector/report-protocol-errors-expected.txt:
+        * inspector/report-protocol-errors.html:
+
 2010-12-22  Andrei Popescu  <andreip@google.com>
 
         Unreviewed buildfix.
index e44fca9..4134613 100644 (file)
@@ -90,6 +90,13 @@ InspectorTest.captureStackTrace = function(callFrames)
     }
 };
 
+InspectorTest.setBreakpoint = function(url, lineNumber, enabled, condition)
+{
+    var scripts = WebInspector.debuggerModel.scriptsForURL(url);
+    for (var i = 0; i < scripts.length; ++i)
+        WebInspector.debuggerModel.setBreakpoint(scripts[i].sourceID, lineNumber, enabled, condition);
+}
+
 InspectorTest._pausedScript = function(details)
 {
     InspectorTest.addResult("Script execution paused.");
index fc2c926..2fdc9ef 100644 (file)
@@ -24,7 +24,7 @@ var test = function()
     function step2()
     {
         InspectorTest.addResult("Main resource was shown.");
-        WebInspector.panels.scripts.visibleView.sourceFrame._setBreakpoint(8);
+        InspectorTest.setBreakpoint(WebInspector.mainResource.url, 8, true, "");
         WebInspector.panels.scripts.toggleBreakpointsButton.element.click();
         InspectorTest.reloadPage(step3);
     }
index 4831d42..43260b2 100644 (file)
@@ -22,7 +22,7 @@ var test = function()
     function step2()
     {
         InspectorTest.addResult("Script source was shown.");
-        WebInspector.panels.scripts.visibleView.sourceFrame._setBreakpoint(9);
+        InspectorTest.setBreakpoint(WebInspector.mainResource.url, 9, true, "");
         InspectorTest.runTestFunctionAndWaitUntilPaused(step3);
     }
 
index 2221c84..a5d8dfc 100644 (file)
@@ -84,8 +84,7 @@ Tests that InspectorBackendDispatcher is catching incorrect messages.
     success : false
     errors : {
         0 : "Protocol Error: Debugger handler is not available."
-        1 : "Protocol Error: Argument 'sourceID' with type 'String' was not found."
-        2 : "Protocol Error: Argument 'lineNumber' with type 'Number' was not found."
+        1 : "Protocol Error: Argument 'breakpointId' with type 'String' was not found."
     }
 }
 {
index d48961d..4c0ff6d 100644 (file)
@@ -17,7 +17,7 @@ function test()
         '{"seq":4,"command":"resourceContent","arguments":{}}',
         '{"seq":5,"command":"resourceContent","arguments":{"identifier":"not a number"}}',
         '{"seq":6,"command":"removeBreakpoint","arguments":{}}',
-        '{"seq":7,"command":"removeBreakpoint","arguments":{"sourceID":"someSourceId","lineNumber":0}}',
+        '{"seq":7,"command":"removeBreakpoint","arguments":{"breakpointId":"someBreakpointId"}}',
 
     ];
     var numberOfReports = 0;
index 502bec2..1dd4fdc 100644 (file)
@@ -1,3 +1,51 @@
+2010-12-21  Pavel Podivilov  <podivilov@chromium.org>
+
+        Reviewed by Yury Semikhatsky.
+
+        Web Inspector: persist JavaScript breakpoints in frontend settings.
+        https://bugs.webkit.org/show_bug.cgi?id=48434
+
+        * 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):
+        (WebCore::ScriptDebugServer::removeBreakpoint):
+        * bindings/v8/ScriptDebugServer.h:
+        * inspector/Inspector.idl:
+        * inspector/InspectorBackend.cpp:
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        (WebCore::InspectorController::enableDebuggerFromFrontend):
+        (WebCore::InspectorController::setStickyBreakpoints):
+        (WebCore::InspectorController::restoreStickyBreakpoint):
+        * inspector/InspectorController.h:
+        * inspector/InspectorDebuggerAgent.cpp:
+        (WebCore::InspectorDebuggerAgent::InspectorDebuggerAgent):
+        (WebCore::InspectorDebuggerAgent::setStickyBreakpoint):
+        (WebCore::InspectorDebuggerAgent::setBreakpoint):
+        (WebCore::InspectorDebuggerAgent::removeBreakpoint):
+        (WebCore::InspectorDebuggerAgent::restoreBreakpoint):
+        (WebCore::InspectorDebuggerAgent::clearForPageNavigation):
+        (WebCore::InspectorDebuggerAgent::didParseSource):
+        * inspector/InspectorDebuggerAgent.h:
+        * inspector/front-end/Breakpoint.js:
+        (WebInspector.Breakpoint):
+        (WebInspector.Breakpoint.prototype.remove):
+        * inspector/front-end/BreakpointManager.js:
+        (WebInspector.BreakpointManager):
+        (WebInspector.DOMBreakpoint.prototype._serializeToJSON):
+        (WebInspector.JavaScriptBreakpoint):
+        (WebInspector.XHRBreakpoint.prototype._serializeToJSON):
+        * inspector/front-end/DebuggerModel.js:
+        (WebInspector.DebuggerModel):
+        * inspector/front-end/ScriptsPanel.js:
+        (WebInspector.ScriptsPanel.prototype._debuggerPaused):
+        * inspector/front-end/SourceFrame.js:
+
 2010-12-22  Dirk Schulze  <krit@wbekit.org>
 
         Reviewed by Nikolas Zimmermann.
index a440b81..10df223 100644 (file)
@@ -50,6 +50,7 @@
 #include <debugger/DebuggerCallFrame.h>
 #include <parser/SourceCode.h>
 #include <runtime/JSLock.h>
+#include <wtf/text/StringConcatenate.h>
 #include <wtf/MainThread.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/UnusedParam.h>
@@ -137,23 +138,33 @@ bool ScriptDebugServer::hasListenersInterestedInPage(Page* page)
     return m_pageListenersMap.contains(page);
 }
 
-bool ScriptDebugServer::setBreakpoint(const String& sourceID, ScriptBreakpoint breakpoint, unsigned lineNumber, unsigned* actualLineNumber)
+String ScriptDebugServer::setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, unsigned* actualLineNumber)
 {
     intptr_t sourceIDValue = sourceID.toIntPtr();
     if (!sourceIDValue)
-        return false;
+        return "";
     BreakpointsMap::iterator it = m_breakpoints.find(sourceIDValue);
     if (it == m_breakpoints.end())
         it = m_breakpoints.set(sourceIDValue, SourceBreakpoints()).first;
-    it->second.set(lineNumber, breakpoint);
+    if (it->second.contains(lineNumber))
+        return "";
+    it->second.set(lineNumber, ScriptBreakpoint(enabled, condition));
     *actualLineNumber = lineNumber;
-    return true;
+    return makeString(sourceID, ":", String::number(lineNumber));
 }
 
-void ScriptDebugServer::removeBreakpoint(const String& sourceID, unsigned lineNumber)
+void ScriptDebugServer::removeBreakpoint(const String& breakpointId)
 {
-    intptr_t sourceIDValue = sourceID.toIntPtr();
-    if (!sourceIDValue)
+    Vector<String> tokens;
+    breakpointId.split(":", tokens);
+    if (tokens.size() != 2)
+        return;
+    bool success;
+    intptr_t sourceIDValue = tokens[0].toIntPtr(&success);
+    if (!success)
+        return;
+    unsigned lineNumber = tokens[1].toUInt(&success);
+    if (!success)
         return;
     BreakpointsMap::iterator it = m_breakpoints.find(sourceIDValue);
     if (it != m_breakpoints.end())
index 3172c65..81cd9ac 100644 (file)
@@ -63,8 +63,8 @@ public:
     void addListener(ScriptDebugListener*, Page*);
     void removeListener(ScriptDebugListener*, Page*);
 
-    bool setBreakpoint(const String& sourceID, ScriptBreakpoint breakpoint, unsigned lineNumber, unsigned* actualLineNumber);
-    void removeBreakpoint(const String& sourceID, unsigned lineNumber);
+    String setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, unsigned* actualLineNumber);
+    void removeBreakpoint(const String& breakpointId);
     void clearBreakpoints();
     void setBreakpointsActivated(bool activated);
     void activateBreakpoints() { setBreakpointsActivated(true); }
index 6026214..50f791d 100644 (file)
@@ -31,7 +31,6 @@
 (function () {
 
 var DebuggerScript = {};
-DebuggerScript._breakpoints = {};
 
 DebuggerScript.PauseOnExceptionsState = {
     DontPauseOnExceptions : 0,
@@ -100,25 +99,13 @@ DebuggerScript.setBreakpoint = function(execState, args)
     var locations = Debug.findBreakPointActualLocations(breakId);
     if (!locations.length)
         return undefined;
-    var actualLineNumber = locations[0].line;
-
-    var key = args.scriptId + ":" + actualLineNumber;
-    if (key in DebuggerScript._breakpoints) {
-        // Remove old breakpoint.
-        Debug.findBreakPoint(DebuggerScript._breakpoints[key], true);
-    }
-    DebuggerScript._breakpoints[key] = breakId;
-    return DebuggerScript._v8ToWebkitLineNumber(actualLineNumber);
+    args.lineNumber = DebuggerScript._v8ToWebkitLineNumber(locations[0].line);
+    return breakId.toString();
 }
 
 DebuggerScript.removeBreakpoint = function(execState, args)
 {
-    args.lineNumber = DebuggerScript._webkitToV8LineNumber(args.lineNumber);
-    var key = args.scriptId + ":" + args.lineNumber;
-    var breakId = DebuggerScript._breakpoints[key];
-    if (breakId)
-        Debug.findBreakPoint(breakId, true);
-    delete DebuggerScript._breakpoints[key];
+    Debug.findBreakPoint(args.breakpointId, true);
 }
 
 DebuggerScript.pauseOnExceptionsState = function()
@@ -190,11 +177,7 @@ DebuggerScript.editScriptSource = function(scriptId, newSource)
 
 DebuggerScript.clearBreakpoints = function(execState, args)
 {
-    for (var key in DebuggerScript._breakpoints) {
-        var breakId = DebuggerScript._breakpoints[key];
-        Debug.findBreakPoint(breakId, true);
-    }
-    DebuggerScript._breakpoints = {};
+    Debug.clearAllBreakPoints();
 }
 
 DebuggerScript.setBreakpointsActivated = function(execState, args)
index 9dfca55..4b4611a 100644 (file)
@@ -143,7 +143,7 @@ void ScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page
     // FIXME: Remove all breakpoints set by the agent.
 }
 
-bool ScriptDebugServer::setBreakpoint(const String& sourceID, ScriptBreakpoint breakpoint, unsigned lineNumber, unsigned* actualLineNumber)
+String ScriptDebugServer::setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, unsigned* actualLineNumber)
 {
     v8::HandleScope scope;
     v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
@@ -152,27 +152,25 @@ bool ScriptDebugServer::setBreakpoint(const String& sourceID, ScriptBreakpoint b
     v8::Local<v8::Object> args = v8::Object::New();
     args->Set(v8::String::New("scriptId"), v8String(sourceID));
     args->Set(v8::String::New("lineNumber"), v8::Integer::New(lineNumber));
-    args->Set(v8::String::New("condition"), v8String(breakpoint.condition));
-    args->Set(v8::String::New("enabled"), v8::Boolean::New(breakpoint.enabled));
+    args->Set(v8::String::New("condition"), v8String(condition));
+    args->Set(v8::String::New("enabled"), v8::Boolean::New(enabled));
 
     v8::Handle<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("setBreakpoint")));
-    v8::Handle<v8::Value> result = v8::Debug::Call(setBreakpointFunction, args);
-    if (!result->IsNumber())
-        return false;
-    ASSERT(result->Int32Value() >= 0);
-    *actualLineNumber = result->Int32Value();
-    return true;
+    v8::Handle<v8::Value> breakpointId = v8::Debug::Call(setBreakpointFunction, args);
+    if (!breakpointId->IsString())
+        return "";
+    *actualLineNumber = args->Get(v8::String::New("lineNumber"))->Int32Value();
+    return v8StringToWebCoreString(breakpointId->ToString());
 }
 
-void ScriptDebugServer::removeBreakpoint(const String& sourceID, unsigned lineNumber)
+void ScriptDebugServer::removeBreakpoint(const String& breakpointId)
 {
     v8::HandleScope scope;
     v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     v8::Context::Scope contextScope(debuggerContext);
 
     v8::Local<v8::Object> args = v8::Object::New();
-    args->Set(v8::String::New("scriptId"), v8String(sourceID));
-    args->Set(v8::String::New("lineNumber"), v8::Integer::New(lineNumber));
+    args->Set(v8::String::New("breakpointId"), v8String(breakpointId));
 
     v8::Handle<v8::Function> removeBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("removeBreakpoint")));
     v8::Debug::Call(removeBreakpointFunction, args);
index 5c5d6c6..40dd5fc 100644 (file)
@@ -55,8 +55,8 @@ public:
     void addListener(ScriptDebugListener*, Page*);
     void removeListener(ScriptDebugListener*, Page*);
 
-    bool setBreakpoint(const String& sourceID, ScriptBreakpoint breakpoint, unsigned lineNumber, unsigned* actualLineNumber);
-    void removeBreakpoint(const String& sourceID, unsigned lineNumber);
+    String setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, unsigned* actualLineNumber);
+    void removeBreakpoint(const String& breakpointId);
     void clearBreakpoints();
     void setBreakpointsActivated(bool activated);
     void activateBreakpoints() { setBreakpointsActivated(true); }
index 12e723d..a593857 100644 (file)
@@ -218,8 +218,8 @@ module core {
         [domain=Debugger] void activateBreakpoints();
         [domain=Debugger] void deactivateBreakpoints();
 
-        [domain=Debugger] void setBreakpoint(in String sourceID, in unsigned int lineNumber, in boolean enabled, in String condition, out boolean success, out unsigned int actualLineNumber);
-        [domain=Debugger] void removeBreakpoint(in String sourceID, in unsigned long lineNumber);
+        [domain=Debugger] void setBreakpoint(in String sourceID, in unsigned int lineNumber, in String condition, in boolean enabled, out String breakpointId, out unsigned int actualLineNumber);
+        [domain=Debugger] void removeBreakpoint(in String breakpointId);
 
         [domain=Inspector] void setStickyBreakpoints(in Object breakpoints); // FIXME: Move to newly introduced BrowserDebugger.
 
@@ -245,7 +245,7 @@ module core {
         [domain=Debugger] void editScriptSource(in String sourceID, in String newContent, out boolean success, out String result, out Value newCallFrames);
         [domain=Debugger] void getScriptSource(in String sourceID, out String scriptSource);
 
-        [notify, domain=Debugger] void breakpointRestored(out String sourceID, out String url, out int line, out boolean enabled, out String condition); // FIXME: should be breakpointResolved
+        [notify, domain=Debugger] void breakpointResolved(out String breakpointId, out String sourceID, out unsigned int lineNumber, out String condition, out boolean enabled, out unsigned int originalLineNumber);
 
 #if defined(ENABLE_WORKERS) && ENABLE_WORKERS
         [notify, domain=Debugger] void didCreateWorker(out long id, out String url, out boolean isShared);
index 791e3a6..eb4c0e7 100644 (file)
@@ -42,7 +42,6 @@
 #include "InspectorDOMAgent.h"
 #include "InspectorFrontend.h"
 #include "InspectorStorageAgent.h"
-#include "ScriptBreakpoint.h"
 #include "ScriptProfiler.h"
 #include "SerializedScriptValue.h"
 
index 2332d87..c882c17 100644 (file)
@@ -150,7 +150,6 @@ InspectorController::InspectorController(Page* page, InspectorClient* client)
 #if ENABLE(JAVASCRIPT_DEBUGGER)
     , m_attachDebuggerWhenShown(false)
     , m_hasXHRBreakpointWithEmptyURL(false)
-    , m_stickyBreakpointsRestored(false)
     , m_profilerAgent(InspectorProfilerAgent::create(this))
 #endif
 {
@@ -1349,6 +1348,7 @@ void InspectorController::enableDebuggerFromFrontend(bool always)
     ASSERT(m_inspectedPage);
 
     m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend.get());
+    restoreStickyBreakpoints();
 
     m_frontend->debuggerWasEnabled();
 }
@@ -1396,10 +1396,6 @@ void InspectorController::resume()
 void InspectorController::setStickyBreakpoints(PassRefPtr<InspectorObject> breakpoints)
 {
     m_state->setObject(InspectorState::stickyBreakpoints, breakpoints);
-    if (!m_stickyBreakpointsRestored) {
-        restoreStickyBreakpoints();
-        m_stickyBreakpointsRestored = true;
-    }
 }
 
 void InspectorController::restoreStickyBreakpoints()
@@ -1420,8 +1416,9 @@ void InspectorController::restoreStickyBreakpoints()
 
 void InspectorController::restoreStickyBreakpoint(PassRefPtr<InspectorObject> breakpoint)
 {
-    DEFINE_STATIC_LOCAL(String, eventListenerNativeBreakpointType, ("EventListener"));
-    DEFINE_STATIC_LOCAL(String, xhrNativeBreakpointType, ("XHR"));
+    DEFINE_STATIC_LOCAL(String, eventListenerBreakpointType, ("EventListener"));
+    DEFINE_STATIC_LOCAL(String, javaScriptBreakpointType, ("JS"));
+    DEFINE_STATIC_LOCAL(String, xhrBreakpointType, ("XHR"));
 
     if (!breakpoint)
         return;
@@ -1429,17 +1426,33 @@ void InspectorController::restoreStickyBreakpoint(PassRefPtr<InspectorObject> br
     if (!breakpoint->getString("type", &type))
         return;
     bool enabled;
-    if (!breakpoint->getBoolean("enabled", &enabled) || !enabled)
+    if (!breakpoint->getBoolean("enabled", &enabled))
         return;
     RefPtr<InspectorObject> condition = breakpoint->getObject("condition");
     if (!condition)
         return;
 
-    if (type == eventListenerNativeBreakpointType) {
+    if (type == eventListenerBreakpointType) {
+        if (!enabled)
+            return;
         String eventName;
         if (condition->getString("eventName", &eventName))
             setEventListenerBreakpoint(eventName);
-    } else if (type == xhrNativeBreakpointType) {
+    } else if (type == javaScriptBreakpointType) {
+        String url;
+        if (!condition->getString("url", &url))
+            return;
+        double lineNumber;
+        if (!condition->getNumber("lineNumber", &lineNumber))
+            return;
+        String javaScriptCondition;
+        if (!condition->getString("condition", &javaScriptCondition))
+            return;
+        if (m_debuggerAgent)
+            m_debuggerAgent->setStickyBreakpoint(url, lineNumber, javaScriptCondition, enabled);
+    } else if (type == xhrBreakpointType) {
+        if (!enabled)
+            return;
         String url;
         if (condition->getString("url", &url))
             setXHRBreakpoint(url);
@@ -1513,26 +1526,6 @@ void InspectorController::didEvaluateForTestInFrontend(long callId, const String
     function.call();
 }
 
-#if ENABLE(JAVASCRIPT_DEBUGGER)
-String InspectorController::breakpointsSettingKey()
-{
-    DEFINE_STATIC_LOCAL(String, keyPrefix, ("breakpoints:"));
-    return keyPrefix + InspectorDebuggerAgent::md5Base16(m_inspectedPage->mainFrame()->loader()->url().string());
-}
-
-PassRefPtr<InspectorValue> InspectorController::loadBreakpoints()
-{
-    String jsonString;
-    m_client->populateSetting(breakpointsSettingKey(), &jsonString);
-    return InspectorValue::parseJSON(jsonString);
-}
-
-void InspectorController::saveBreakpoints(PassRefPtr<InspectorObject> breakpoints)
-{
-    m_client->storeSetting(breakpointsSettingKey(), breakpoints->toJSONString());
-}
-#endif
-
 static Path quadToPath(const FloatQuad& quad)
 {
     Path quadPath;
index f55090c..e570c98 100644 (file)
@@ -335,13 +335,6 @@ private:
 
     void didEvaluateForTestInFrontend(long callId, const String& jsonResult);
 
-#if ENABLE(JAVASCRIPT_DEBUGGER)
-    friend class InspectorDebuggerAgent;
-    String breakpointsSettingKey();
-    PassRefPtr<InspectorValue> loadBreakpoints();
-    void saveBreakpoints(PassRefPtr<InspectorObject> breakpoints);
-#endif
-
     Page* m_inspectedPage;
     InspectorClient* m_client;
     OwnPtr<InspectorFrontendClient> m_inspectorFrontendClient;
@@ -395,7 +388,6 @@ private:
     HashSet<String> m_eventListenerBreakpoints;
     HashSet<String> m_XHRBreakpoints;
     bool m_hasXHRBreakpointWithEmptyURL;
-    bool m_stickyBreakpointsRestored;
 
     OwnPtr<InspectorProfilerAgent> m_profilerAgent;
 #endif
index 0b18b0c..0046989 100644 (file)
 #include "InspectorValues.h"
 #include "PlatformString.h"
 #include "ScriptDebugServer.h"
-#include <wtf/MD5.h>
-#include <wtf/text/StringConcatenate.h>
 
 namespace WebCore {
 
-static String formatBreakpointId(const String& sourceID, unsigned lineNumber)
-{
-    return makeString(sourceID, ':', String::number(lineNumber));
-}
-
 PassOwnPtr<InspectorDebuggerAgent> InspectorDebuggerAgent::create(InspectorController* inspectorController, InspectorFrontend* frontend)
 {
     OwnPtr<InspectorDebuggerAgent> agent = adoptPtr(new InspectorDebuggerAgent(inspectorController, frontend));
@@ -61,7 +54,6 @@ InspectorDebuggerAgent::InspectorDebuggerAgent(InspectorController* inspectorCon
     : m_inspectorController(inspectorController)
     , m_frontend(frontend)
     , m_pausedScriptState(0)
-    , m_breakpointsLoaded(false)
     , m_javaScriptPauseScheduled(false)
 {
 }
@@ -87,49 +79,37 @@ void InspectorDebuggerAgent::deactivateBreakpoints()
     ScriptDebugServer::shared().deactivateBreakpoints();
 }
 
-void InspectorDebuggerAgent::setBreakpoint(const String& sourceID, unsigned lineNumber, bool enabled, const String& condition, bool* success, unsigned int* actualLineNumber)
+void InspectorDebuggerAgent::setStickyBreakpoint(const String& url, unsigned lineNumber, const String& condition, bool enabled)
 {
-    ScriptBreakpoint breakpoint(enabled, condition);
-    *success = ScriptDebugServer::shared().setBreakpoint(sourceID, breakpoint, lineNumber, actualLineNumber);
-    if (!*success)
-        return;
+    HashMap<String, ScriptBreakpoints>::iterator it = m_stickyBreakpoints.find(url);
+    if (it == m_stickyBreakpoints.end())
+        it = m_stickyBreakpoints.set(url, ScriptBreakpoints()).first;
+    it->second.set(lineNumber, Breakpoint(condition, enabled));
 
-    String url = m_sourceIDToURL.get(sourceID);
-    if (url.isEmpty())
+    URLToSourceIDsMap::iterator urlToSourceIDsIterator = m_urlToSourceIDs.find(url);
+    if (urlToSourceIDsIterator == m_urlToSourceIDs.end())
         return;
-
-    String breakpointId = formatBreakpointId(sourceID, *actualLineNumber);
-    m_breakpointsMapping.set(breakpointId, *actualLineNumber);
-
-    String key = md5Base16(url);
-    HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(key);
-    if (it == m_stickyBreakpoints.end())
-        it = m_stickyBreakpoints.set(key, SourceBreakpoints()).first;
-    it->second.set(*actualLineNumber, breakpoint);
-    saveBreakpoints();
+    const Vector<String>& sourceIDs = urlToSourceIDsIterator->second;
+    for (size_t i = 0; i < sourceIDs.size(); ++i)
+        restoreBreakpoint(sourceIDs[i], lineNumber, condition, enabled);
 }
 
-void InspectorDebuggerAgent::removeBreakpoint(const String& sourceID, unsigned lineNumber)
+void InspectorDebuggerAgent::setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, String* breakpointId, unsigned int* actualLineNumber)
 {
-    ScriptDebugServer::shared().removeBreakpoint(sourceID, lineNumber);
-
-    String url = m_sourceIDToURL.get(sourceID);
-    if (url.isEmpty())
-        return;
-
-    String breakpointId = formatBreakpointId(sourceID, lineNumber);
-    HashMap<String, unsigned>::iterator mappingIt = m_breakpointsMapping.find(breakpointId);
-    if (mappingIt == m_breakpointsMapping.end())
-        return;
-    unsigned stickyLine = mappingIt->second;
-    m_breakpointsMapping.remove(mappingIt);
+    *breakpointId = ScriptDebugServer::shared().setBreakpoint(sourceID, lineNumber, condition, enabled, actualLineNumber);
+}
 
-    HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(md5Base16(url));
-    if (it == m_stickyBreakpoints.end())
-        return;
+void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId)
+{
+    ScriptDebugServer::shared().removeBreakpoint(breakpointId);
+}
 
-    it->second.remove(stickyLine);
-    saveBreakpoints();
+void InspectorDebuggerAgent::restoreBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled)
+{
+    unsigned actualLineNumber = 0;
+    String breakpointId = ScriptDebugServer::shared().setBreakpoint(sourceID, lineNumber, condition, enabled, &actualLineNumber);
+    if (!breakpointId.isEmpty())
+        m_frontend->breakpointResolved(breakpointId, sourceID, actualLineNumber, condition, enabled, lineNumber);
 }
 
 void InspectorDebuggerAgent::editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames)
@@ -200,28 +180,9 @@ long InspectorDebuggerAgent::pauseOnExceptionsState()
 
 void InspectorDebuggerAgent::clearForPageNavigation()
 {
-    m_sourceIDToURL.clear();
     m_scriptIDToContent.clear();
+    m_urlToSourceIDs.clear();
     m_stickyBreakpoints.clear();
-    m_breakpointsMapping.clear();
-    m_breakpointsLoaded = false;
-}
-
-String InspectorDebuggerAgent::md5Base16(const String& string)
-{
-    static const char digits[] = "0123456789abcdef";
-
-    MD5 md5;
-    md5.addBytes(reinterpret_cast<const uint8_t*>(string.characters()), string.length() * 2);
-    Vector<uint8_t, 16> digest;
-    md5.checksum(digest);
-
-    Vector<char, 32> result;
-    for (int i = 0; i < 16; ++i) {
-        result.append(digits[(digest[i] >> 4) & 0xf]);
-        result.append(digits[digest[i] & 0xf]);
-    }
-    return String(result.data(), result.size());
 }
 
 PassRefPtr<InspectorValue> InspectorDebuggerAgent::currentCallFrames()
@@ -236,39 +197,6 @@ PassRefPtr<InspectorValue> InspectorDebuggerAgent::currentCallFrames()
     return injectedScript.callFrames();
 }
 
-void InspectorDebuggerAgent::loadBreakpoints()
-{
-    if (m_breakpointsLoaded)
-        return;
-    m_breakpointsLoaded = true;
-
-    RefPtr<InspectorValue> parsedSetting = m_inspectorController->loadBreakpoints();
-    if (!parsedSetting)
-        return;
-    RefPtr<InspectorObject> breakpoints = parsedSetting->asObject();
-    if (!breakpoints)
-        return;
-    for (InspectorObject::iterator it = breakpoints->begin(); it != breakpoints->end(); ++it) {
-        RefPtr<InspectorObject> breakpointsForURL = it->second->asObject();
-        if (!breakpointsForURL)
-            continue;
-        HashMap<String, SourceBreakpoints>::iterator sourceBreakpointsIt = m_stickyBreakpoints.set(it->first, SourceBreakpoints()).first;
-        ScriptBreakpoint::sourceBreakpointsFromInspectorObject(breakpointsForURL, &sourceBreakpointsIt->second);
-    }
-}
-
-void InspectorDebuggerAgent::saveBreakpoints()
-{
-    RefPtr<InspectorObject> breakpoints = InspectorObject::create();
-    for (HashMap<String, SourceBreakpoints>::iterator it(m_stickyBreakpoints.begin()); it != m_stickyBreakpoints.end(); ++it) {
-        if (it->second.isEmpty())
-            continue;
-        RefPtr<InspectorObject> breakpointsForURL = ScriptBreakpoint::inspectorObjectFromSourceBreakpoints(it->second);
-        breakpoints->setObject(it->first, breakpointsForURL);
-    }
-    m_inspectorController->saveBreakpoints(breakpoints);
-}
-
 // JavaScriptDebugListener functions
 
 void InspectorDebuggerAgent::didParseSource(const String& sourceID, const String& url, const String& data, int firstLine, ScriptWorldType worldType)
@@ -281,23 +209,20 @@ void InspectorDebuggerAgent::didParseSource(const String& sourceID, const String
     if (url.isEmpty())
         return;
 
-    loadBreakpoints();
-    HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(md5Base16(url));
-    if (it != m_stickyBreakpoints.end()) {
-        for (SourceBreakpoints::iterator breakpointIt = it->second.begin(); breakpointIt != it->second.end(); ++breakpointIt) {
-            int lineNumber = breakpointIt->first;
-            if (firstLine > lineNumber)
-                continue;
-            unsigned actualLineNumber = 0;
-            bool success = ScriptDebugServer::shared().setBreakpoint(sourceID, breakpointIt->second, lineNumber, &actualLineNumber);
-            if (!success)
-                continue;
-            m_frontend->breakpointRestored(sourceID, url, actualLineNumber, breakpointIt->second.enabled, breakpointIt->second.condition);
-            String breakpointId = formatBreakpointId(sourceID, actualLineNumber);
-            m_breakpointsMapping.set(breakpointId, lineNumber);
-        }
+    URLToSourceIDsMap::iterator urlToSourceIDsIterator = m_urlToSourceIDs.find(url);
+    if (urlToSourceIDsIterator == m_urlToSourceIDs.end())
+        urlToSourceIDsIterator = m_urlToSourceIDs.set(url, Vector<String>()).first;
+    urlToSourceIDsIterator->second.append(sourceID);
+
+    HashMap<String, ScriptBreakpoints>::iterator stickyBreakpointsIterator = m_stickyBreakpoints.find(url);
+    if (stickyBreakpointsIterator == m_stickyBreakpoints.end())
+        return;
+
+    const ScriptBreakpoints& breakpoints = stickyBreakpointsIterator->second;
+    for (ScriptBreakpoints::const_iterator it = breakpoints.begin(); it != breakpoints.end(); ++it) {
+        const Breakpoint& breakpoint = it->second;
+        restoreBreakpoint(sourceID, it->first, breakpoint.first, breakpoint.second);
     }
-    m_sourceIDToURL.set(sourceID, url);
 }
 
 void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
index adc925a..6e45e59 100644 (file)
 #define InspectorDebuggerAgent_h
 
 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
-#include "ScriptBreakpoint.h"
 #include "ScriptDebugListener.h"
 #include "ScriptState.h"
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
 #include <wtf/text/StringHash.h>
 
 namespace WebCore {
@@ -61,8 +61,9 @@ public:
 
     void activateBreakpoints();
     void deactivateBreakpoints();
-    void setBreakpoint(const String& sourceID, unsigned lineNumber, bool enabled, const String& condition, bool* success, unsigned int* actualLineNumber);
-    void removeBreakpoint(const String& sourceID, unsigned lineNumber);
+    void setStickyBreakpoint(const String& url, unsigned lineNumber, const String& condition, bool enabled);
+    void setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, String* breakpointId, unsigned int* actualLineNumber);
+    void removeBreakpoint(const String& breakpointId);
 
     void editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames);
     void getScriptSource(const String& sourceID, String* scriptSource);
@@ -81,30 +82,27 @@ public:
 
     void clearForPageNavigation();
 
-    static String md5Base16(const String& string);
-
 private:
     InspectorDebuggerAgent(InspectorController*, InspectorFrontend*);
 
     PassRefPtr<InspectorValue> currentCallFrames();
 
-    void loadBreakpoints();
-    void saveBreakpoints();
-
     virtual void didParseSource(const String& sourceID, const String& url, const String& data, int firstLine, ScriptWorldType);
     virtual void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage);
     virtual void didPause(ScriptState*);
     virtual void didContinue();
 
+    void restoreBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled);
+
     InspectorController* m_inspectorController;
     InspectorFrontend* m_frontend;
     ScriptState* m_pausedScriptState;
-    HashMap<String, String> m_sourceIDToURL;
     HashMap<String, String> m_scriptIDToContent;
-    HashMap<String, SourceBreakpoints> m_stickyBreakpoints;
-    HashMap<String, unsigned> m_breakpointsMapping;
-    bool m_breakpointsLoaded;
-    static InspectorDebuggerAgent* s_debuggerAgentOnBreakpoint;
+    typedef HashMap<String, Vector<String> > URLToSourceIDsMap;
+    URLToSourceIDsMap m_urlToSourceIDs;
+    typedef std::pair<String, bool> Breakpoint;
+    typedef HashMap<unsigned, Breakpoint> ScriptBreakpoints;
+    HashMap<String, ScriptBreakpoints> m_stickyBreakpoints;
     RefPtr<InspectorObject> m_breakProgramDetails;
     bool m_javaScriptPauseScheduled;
 };
index 32a6a3d..dd0ce12 100644 (file)
@@ -29,8 +29,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.Breakpoint = function(debuggerModel, sourceID, url, line, enabled, condition)
+WebInspector.Breakpoint = function(debuggerModel, breakpointId, sourceID, url, line, enabled, condition)
 {
+    this.id = breakpointId;
     this.url = url;
     this.line = line;
     this.sourceID = sourceID;
@@ -41,27 +42,12 @@ WebInspector.Breakpoint = function(debuggerModel, sourceID, url, line, enabled,
     this._debuggerModel = debuggerModel;
 }
 
-WebInspector.Breakpoint.jsBreakpointId = function(sourceID, line)
-{
-    return sourceID + ":" + line;
-}
-
 WebInspector.Breakpoint.prototype = {
     get enabled()
     {
         return this._enabled;
     },
 
-    set enabled(x)
-    {
-        if (this._enabled === x)
-            return;
-
-        this._enabled = x;
-        this._debuggerModel._setBreakpointOnBackend(this);
-        this.dispatchEventToListeners("enable-changed");
-    },
-
     get sourceText()
     {
         return this._sourceText;
@@ -73,28 +59,11 @@ WebInspector.Breakpoint.prototype = {
         this.dispatchEventToListeners("label-changed");
     },
 
-    get id()
-    {
-        return WebInspector.Breakpoint.jsBreakpointId(this.sourceID, this.line);
-    },
-
     get condition()
     {
         return this._condition;
     },
 
-    set condition(c)
-    {
-        c = c || "";
-        if (this._condition === c)
-            return;
-
-        this._condition = c;
-        if (this.enabled)
-            this._debuggerModel._setBreakpointOnBackend(this);
-        this.dispatchEventToListeners("condition-changed");
-    },
-
     get hit()
     {
         return this._hit;
@@ -134,7 +103,7 @@ WebInspector.Breakpoint.prototype = {
 
     remove: function()
     {
-        InspectorBackend.removeBreakpoint(this.sourceID, this.line);
+        this._debuggerModel.removeBreakpoint(this.id);
         this.dispatchEventToListeners("removed");
         this.removeAllListeners();
         delete this._debuggerModel;
index 604da60..82b55b1 100644 (file)
@@ -36,16 +36,20 @@ WebInspector.BreakpointManager = function()
         this._stickyBreakpoints[projectId] = this._validateBreakpoints(breakpoints[projectId]);
     InspectorBackend.setStickyBreakpoints(this._stickyBreakpoints);
 
-    this._nativeBreakpoints = {};
+    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.NativeBreakpointTypes = {
+WebInspector.BreakpointManager.BreakpointTypes = {
     DOM: "DOM",
+    JS: "JS",
     EventListener: "EventListener",
     XHR: "XHR"
 }
@@ -70,11 +74,11 @@ WebInspector.BreakpointManager.prototype = {
             return;
 
         var breakpointId = this._createDOMBreakpointId(nodeId, type);
-        if (breakpointId in this._nativeBreakpoints)
+        if (breakpointId in this._breakpoints)
             return;
 
         var breakpoint = new WebInspector.DOMBreakpoint(node, type);
-        this._setNativeBreakpoint(breakpointId, breakpoint, enabled, restored);
+        this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
         if (enabled && restored)
             breakpoint._enable();
 
@@ -90,16 +94,48 @@ WebInspector.BreakpointManager.prototype = {
     _createEventListenerBreakpoint: function(eventName, enabled, restored)
     {
         var breakpointId = this._createEventListenerBreakpointId(eventName);
-        if (breakpointId in this._nativeBreakpoints)
+        if (breakpointId in this._breakpoints)
             return;
 
         var breakpoint = new WebInspector.EventListenerBreakpoint(eventName);
-        this._setNativeBreakpoint(breakpointId, breakpoint, enabled, restored);
+        this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
 
         breakpoint.view = new WebInspector.EventListenerBreakpointView(this, breakpointId, enabled, eventName);
         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);
@@ -108,19 +144,19 @@ WebInspector.BreakpointManager.prototype = {
     _createXHRBreakpoint: function(url, enabled, restored)
     {
         var breakpointId = this._createXHRBreakpointId(url);
-        if (breakpointId in this._nativeBreakpoints)
+        if (breakpointId in this._breakpoints)
             return;
 
         var breakpoint = new WebInspector.XHRBreakpoint(url);
-        this._setNativeBreakpoint(breakpointId, breakpoint, enabled, restored);
+        this._setBreakpoint(breakpointId, breakpoint, enabled, restored);
 
         breakpoint.view = new WebInspector.XHRBreakpointView(this, breakpointId, enabled, url);
         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.XHRBreakpointAdded, breakpoint.view);
     },
 
-    _setNativeBreakpoint: function(breakpointId, breakpoint, enabled, restored)
+    _setBreakpoint: function(breakpointId, breakpoint, enabled, restored)
     {
-        this._nativeBreakpoints[breakpointId] = breakpoint;
+        this._breakpoints[breakpointId] = breakpoint;
         breakpoint.enabled = enabled;
         if (restored)
             return;
@@ -129,9 +165,9 @@ WebInspector.BreakpointManager.prototype = {
         this._saveBreakpoints();
     },
 
-    _setNativeBreakpointEnabled: function(breakpointId, enabled)
+    _setBreakpointEnabled: function(breakpointId, enabled)
     {
-        var breakpoint = this._nativeBreakpoints[breakpointId];
+        var breakpoint = this._breakpoints[breakpointId];
         if (breakpoint.enabled === enabled)
             return;
         if (enabled)
@@ -142,25 +178,28 @@ WebInspector.BreakpointManager.prototype = {
         this._saveBreakpoints();
     },
 
-    _removeNativeBreakpoint: function(breakpointId)
+    _removeBreakpoint: function(breakpointId)
     {
-        var breakpoint = this._nativeBreakpoints[breakpointId];
+        var breakpoint = this._breakpoints[breakpointId];
         if (breakpoint.enabled)
             breakpoint._disable();
-        delete this._nativeBreakpoints[breakpointId];
+        delete this._breakpoints[breakpointId];
         this._saveBreakpoints();
     },
 
     breakpointViewForEventData: function(eventData)
     {
         var breakpointId;
-        if (eventData.breakpointType === WebInspector.BreakpointManager.NativeBreakpointTypes.DOM)
+        if (eventData.breakpointType === WebInspector.BreakpointManager.BreakpointTypes.DOM)
             breakpointId = this._createDOMBreakpointId(eventData.nodeId, eventData.type);
-        else if (eventData.breakpointType === WebInspector.BreakpointManager.NativeBreakpointTypes.EventListener)
+        else if (eventData.breakpointType === WebInspector.BreakpointManager.BreakpointTypes.EventListener)
             breakpointId = this._createEventListenerBreakpointId(eventData.eventName);
-        else if (eventData.breakpointType === WebInspector.BreakpointManager.NativeBreakpointTypes.XHR)
+        else if (eventData.breakpointType === WebInspector.BreakpointManager.BreakpointTypes.XHR)
             breakpointId = this._createXHRBreakpointId(eventData.breakpointURL);
-        var breakpoint = this._nativeBreakpoints[breakpointId];
+        else
+            return;
+
+        var breakpoint = this._breakpoints[breakpointId];
         if (breakpoint)
             return breakpoint.view;
     },
@@ -191,16 +230,19 @@ WebInspector.BreakpointManager.prototype = {
 
     _projectChanged: function(event)
     {
-        this._nativeBreakpoints = {};
+        this._breakpoints = {};
         this._domBreakpointsRestored = false;
+        this._scriptBreakpoints = {};
         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.ProjectChanged);
 
         var breakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || [];
         for (var i = 0; i < breakpoints.length; ++i) {
             var breakpoint = breakpoints[i];
-            if (breakpoint.type === WebInspector.BreakpointManager.NativeBreakpointTypes.EventListener)
+            if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.EventListener)
                 this._createEventListenerBreakpoint(breakpoint.condition.eventName, breakpoint.enabled, true);
-            else if (breakpoint.type === WebInspector.BreakpointManager.NativeBreakpointTypes.XHR)
+            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);
         }
     },
@@ -215,7 +257,7 @@ WebInspector.BreakpointManager.prototype = {
                 return;
             for (var i = 0; i < breakpoints.length; ++i) {
                 var breakpoint = breakpoints[i];
-                if (breakpoint.type !== WebInspector.BreakpointManager.NativeBreakpointTypes.DOM)
+                if (breakpoint.type !== WebInspector.BreakpointManager.BreakpointTypes.DOM)
                     continue;
                 var nodeId = pathToNodeId[breakpoint.condition.path];
                 if (nodeId)
@@ -229,7 +271,7 @@ WebInspector.BreakpointManager.prototype = {
         var pathToNodeId = {};
         var pendingCalls = 0;
         for (var i = 0; i < breakpoints.length; ++i) {
-            if (breakpoints[i].type !== WebInspector.BreakpointManager.NativeBreakpointTypes.DOM)
+            if (breakpoints[i].type !== WebInspector.BreakpointManager.BreakpointTypes.DOM)
                 continue;
             var path = breakpoints[i].condition.path;
             if (path in pathToNodeId)
@@ -245,8 +287,8 @@ WebInspector.BreakpointManager.prototype = {
     _saveBreakpoints: function()
     {
         var breakpoints = [];
-        for (var breakpointId in this._nativeBreakpoints) {
-            var breakpoint = this._nativeBreakpoints[breakpointId];
+        for (var breakpointId in this._breakpoints) {
+            var breakpoint = this._breakpoints[breakpointId];
             var persistentBreakpoint = breakpoint._serializeToJSON();
             persistentBreakpoint.enabled = breakpoint.enabled;
             breakpoints.push(persistentBreakpoint);
@@ -254,7 +296,7 @@ WebInspector.BreakpointManager.prototype = {
         if (!this._domBreakpointsRestored) {
             var stickyBreakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || [];
             for (var i = 0; i < stickyBreakpoints.length; ++i) {
-                if (stickyBreakpoints[i].type === WebInspector.BreakpointManager.NativeBreakpointTypes.DOM)
+                if (stickyBreakpoints[i].type === WebInspector.BreakpointManager.BreakpointTypes.DOM)
                     breakpoints.push(stickyBreakpoints[i]);
             }
         }
@@ -274,15 +316,19 @@ WebInspector.BreakpointManager.prototype = {
                 continue;
             var id = breakpoint.type + ":";
             var condition = breakpoint.condition;
-            if (breakpoint.type === WebInspector.BreakpointManager.NativeBreakpointTypes.DOM) {
+            if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.DOM) {
                 if (typeof condition.path !== "string" || typeof condition.type !== "number")
                     continue;
                 id += condition.path + ":" + condition.type;
-            } else if (breakpoint.type === WebInspector.BreakpointManager.NativeBreakpointTypes.EventListener) {
+            } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.EventListener) {
                 if (typeof condition.eventName !== "string")
                     continue;
                 id += condition.eventName;
-            } else if (breakpoint.type === WebInspector.BreakpointManager.NativeBreakpointTypes.XHR) {
+            } 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;
@@ -300,6 +346,11 @@ WebInspector.BreakpointManager.prototype = {
         return "dom:" + nodeId + ":" + type;
     },
 
+    _createJavaScriptBreakpointId: function(url, lineNumber)
+    {
+        return "js:" + url + ":" + lineNumber;
+    },
+
     _createEventListenerBreakpointId: function(eventName)
     {
         return "eventListner:" + eventName;
@@ -333,11 +384,34 @@ WebInspector.DOMBreakpoint.prototype = {
 
     _serializeToJSON: function()
     {
-        var type = WebInspector.BreakpointManager.NativeBreakpointTypes.DOM;
+        var type = WebInspector.BreakpointManager.BreakpointTypes.DOM;
         return { type: type, condition: { path: this._path, type: this._type } };
     }
 }
 
+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, condition: this._condition } };
+    }
+}
+
 WebInspector.EventListenerBreakpoint = function(eventName)
 {
     this._eventName = eventName;
@@ -356,7 +430,7 @@ WebInspector.EventListenerBreakpoint.prototype = {
 
     _serializeToJSON: function()
     {
-        var type = WebInspector.BreakpointManager.NativeBreakpointTypes.EventListener;
+        var type = WebInspector.BreakpointManager.BreakpointTypes.EventListener;
         return { type: type, condition: { eventName: this._eventName } };
     }
 }
@@ -379,7 +453,7 @@ WebInspector.XHRBreakpoint.prototype = {
 
     _serializeToJSON: function()
     {
-        var type = WebInspector.BreakpointManager.NativeBreakpointTypes.XHR;
+        var type = WebInspector.BreakpointManager.BreakpointTypes.XHR;
         return { type: type, condition: { url: this._url } };
     }
 }
@@ -402,7 +476,7 @@ WebInspector.NativeBreakpointView.prototype = {
 
     set enabled(enabled)
     {
-        this._manager._setNativeBreakpointEnabled(this._id, enabled);
+        this._manager._setBreakpointEnabled(this._id, enabled);
         this._enabled = enabled;
         this.dispatchEventToListeners("enable-changed");
     },
@@ -420,7 +494,7 @@ WebInspector.NativeBreakpointView.prototype = {
 
     remove: function()
     {
-        this._manager._removeNativeBreakpoint(this._id);
+        this._manager._removeBreakpoint(this._id);
         this._onRemove();
         this.dispatchEventToListeners("removed");
     },
index 31c75e5..5ab0e2d 100644 (file)
@@ -32,7 +32,9 @@ WebInspector.DebuggerModel = function()
 {
     InspectorBackend.registerDomainDispatcher("Debugger", this);
 
+    this._paused = false;
     this._breakpoints = {};
+    this._sourceIDAndLineToBreakpointId = {};
     this._scripts = {};
 }
 
@@ -42,35 +44,68 @@ WebInspector.DebuggerModel.Events = {
     ParsedScriptSource: "parsed-script-source",
     FailedToParseScriptSource: "failed-to-parse-script-source",
     BreakpointAdded: "breakpoint-added",
+    BreakpointRemoved: "breakpoint-removed"
 }
 
 WebInspector.DebuggerModel.prototype = {
-    setOneTimeBreakpoint: function(sourceID, line)
+    continueToLine: function(sourceID, lineNumber)
     {
-        var breakpoint = new WebInspector.Breakpoint(this, sourceID, undefined, line, true, undefined);
-        if (this._breakpoints[breakpoint.id])
-            return;
-        if (this._oneTimeBreakpoint)
-            InspectorBackend.removeBreakpoint(this._oneTimeBreakpoint.sourceID, this._oneTimeBreakpoint.line);
-        this._oneTimeBreakpoint = breakpoint;
-        // FIXME(40669): one time breakpoint will be persisted in inspector settings if not hit.
-        this._setBreakpointOnBackend(breakpoint, true);
+        function didSetBreakpoint(breakpointId, actualLineNumber)
+        {
+            if (!breakpointId)
+                return;
+            if (this.findBreakpoint(sourceID, actualLineNumber)) {
+                InspectorBackend.removeBreakpoint(breakpointId);
+                return;
+            }
+            if ("_continueToLineBreakpointId" in this)
+                InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId);
+            this._continueToLineBreakpointId = breakpointId;
+        }
+        InspectorBackend.setBreakpoint(sourceID, lineNumber, "", true, didSetBreakpoint.bind(this));
+        if (this._paused)
+            InspectorBackend.resume();
     },
 
-    removeOneTimeBreakpoint: function()
+    setBreakpoint: function(sourceID, lineNumber, enabled, condition)
     {
-        if (this._oneTimeBreakpoint) {
-            InspectorBackend.removeBreakpoint(this._oneTimeBreakpoint.sourceID, this._oneTimeBreakpoint.line);
-            delete this._oneTimeBreakpoint;
+        function didSetBreakpoint(breakpointId, actualLineNumber)
+        {
+            if (breakpointId)
+                this._breakpointSetOnBackend(breakpointId, sourceID, actualLineNumber, condition, enabled, lineNumber, false);
         }
+        InspectorBackend.setBreakpoint(sourceID, lineNumber, condition, enabled, didSetBreakpoint.bind(this));
+    },
+
+    removeBreakpoint: function(breakpointId)
+    {
+        InspectorBackend.removeBreakpoint(breakpointId);
+        var breakpoint = this._breakpoints[breakpointId];
+        delete this._breakpoints[breakpointId];
+        delete this._sourceIDAndLineToBreakpointId[this._encodeSourceIDAndLine(breakpoint.sourceID, breakpoint.line)];
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointRemoved, breakpointId);
     },
 
-    setBreakpoint: function(sourceID, line, enabled, condition)
+    breakpointResolved: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber)
     {
+        this._breakpointSetOnBackend(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, true);
+    },
+
+    _breakpointSetOnBackend: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, restored)
+    {
+        var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber);
+        if (sourceIDAndLine in this._sourceIDAndLineToBreakpointId) {
+            InspectorBackend.removeBreakpoint(breakpointId);
+            return;
+        }
+
         var url = this._scripts[sourceID].sourceURL;
-        var breakpoint = this._setBreakpoint(sourceID, url, line, enabled, condition);
-        if (breakpoint)
-            this._setBreakpointOnBackend(breakpoint);
+        var breakpoint = new WebInspector.Breakpoint(this, breakpointId, sourceID, url, lineNumber, enabled, condition);
+        breakpoint.restored = restored;
+        breakpoint.originalLineNumber = originalLineNumber;
+        this._breakpoints[breakpointId] = breakpoint;
+        this._sourceIDAndLineToBreakpointId[sourceIDAndLine] = breakpointId;
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint);
     },
 
     queryBreakpoints: function(filter)
@@ -86,55 +121,25 @@ WebInspector.DebuggerModel.prototype = {
 
     findBreakpoint: function(sourceID, lineNumber)
     {
-        var breakpointId = WebInspector.Breakpoint.jsBreakpointId(sourceID, lineNumber);
+        var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber);
+        var breakpointId = this._sourceIDAndLineToBreakpointId[sourceIDAndLine];
         return this._breakpoints[breakpointId];
     },
 
+    _encodeSourceIDAndLine: function(sourceID, lineNumber)
+    {
+        return sourceID + ":" + lineNumber;
+    },
+
     reset: function()
     {
+        this._paused = false;
         this._breakpoints = {};
         delete this._oneTimeBreakpoint;
+        this._sourceIDAndLineToBreakpointId = {};
         this._scripts = {};
     },
 
-    _setBreakpoint: function(sourceID, url, line, enabled, condition)
-    {
-        var breakpoint = new WebInspector.Breakpoint(this, sourceID, url, line, enabled, condition);
-        if (this._breakpoints[breakpoint.id])
-            return;
-        if (this._oneTimeBreakpoint && (this._oneTimeBreakpoint.id == breakpoint.id))
-            delete this._oneTimeBreakpoint;
-        this._breakpoints[breakpoint.id] = breakpoint;
-        breakpoint.addEventListener("removed", this._breakpointRemoved, this);
-        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint);
-        return breakpoint;
-    },
-
-    _breakpointRemoved: function(event)
-    {
-        delete this._breakpoints[event.target.id];
-    },
-
-    _setBreakpointOnBackend: function(breakpoint, isOneTime)
-    {
-        function didSetBreakpoint(success, line)
-        {
-            if (success && line == breakpoint.line)
-                return;
-            if (isOneTime) {
-                if (success)
-                    this._oneTimeBreakpoint.line = line;
-                else
-                    delete this._oneTimeBreakpoint;
-            } else {
-                breakpoint.remove();
-                if (success)
-                    this._setBreakpoint(breakpoint.sourceID, breakpoint.url, line, breakpoint.enabled, breakpoint.condition);
-            }
-        }
-        InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition, didSetBreakpoint.bind(this));
-    },
-
     scriptForSourceID: function(sourceID)
     {
         return this._scripts[sourceID];
@@ -158,13 +163,13 @@ WebInspector.DebuggerModel.prototype = {
 
     // All the methods below are InspectorBackend notification handlers.
 
-    breakpointRestored: function(sourceID, url, line, enabled, condition)
-    {
-        this._setBreakpoint(sourceID, url, line, enabled, condition);
-    },
-
     pausedScript: function(details)
     {
+        this._paused = true;
+        if ("_continueToLineBreakpointId" in this) {
+            InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId);
+            delete this._continueToLineBreakpointId;
+        }
         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details);
 
         if (details.eventType === WebInspector.DebuggerEventTypes.JavaScriptPause || details.eventType === WebInspector.DebuggerEventTypes.NativeBreakpoint)
@@ -179,6 +184,7 @@ WebInspector.DebuggerModel.prototype = {
 
     resumedScript: function()
     {
+        this._paused = false;
         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
 
         if (!this._lastHitBreakpoint)
index 7387964..56facf2 100644 (file)
@@ -271,13 +271,6 @@ WebInspector.ScriptsPanel.prototype = {
         this._addScriptToFilesMenu(script);
     },
 
-    continueToLine: function(sourceID, line)
-    {
-        WebInspector.debuggerModel.setOneTimeBreakpoint(sourceID, line);
-        if (this.paused)
-            this._togglePause();
-    },
-
     _resourceLoadingFinished: function(e)
     {
         var resource = e.target;
@@ -372,7 +365,6 @@ WebInspector.ScriptsPanel.prototype = {
     {
         var callFrames = event.data.callFrames;
 
-        WebInspector.debuggerModel.removeOneTimeBreakpoint();
         this._paused = true;
         this._waitingToPause = false;
         this._stepping = false;
index 4bead8f..fa8441d 100644 (file)
@@ -482,7 +482,7 @@ WebInspector.SourceFrame.prototype = {
         var breakpoint = this._findBreakpoint(lineNumber);
         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, lineNumber));
+            contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, lineNumber, "", true));
 
             function addConditionalBreakpoint()
             {
@@ -491,7 +491,7 @@ WebInspector.SourceFrame.prototype = {
                 {
                     this._removeBreakpointDecoration(lineNumber);
                     if (committed)
-                        this._setBreakpoint(lineNumber, condition);
+                        this._setBreakpoint(lineNumber, true, condition);
                 }
                 this._editBreakpointCondition(lineNumber, "", didEditBreakpointCondition.bind(this));
             }
@@ -503,16 +503,23 @@ WebInspector.SourceFrame.prototype = {
             {
                 function didEditBreakpointCondition(committed, condition)
                 {
-                    if (committed)
-                        breakpoint.condition = condition;
+                    if (committed) {
+                        breakpoint.remove();
+                        this._setBreakpoint(breakpoint.line, breakpoint.enabled, condition);
+                    }
                 }
-                this._editBreakpointCondition(lineNumber, breakpoint.condition, didEditBreakpointCondition);
+                this._editBreakpointCondition(lineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this));
             }
             contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpointCondition.bind(this));
+            function setBreakpointEnabled(enabled)
+            {
+                breakpoint.remove();
+                this._setBreakpoint(breakpoint.line, enabled, breakpoint.condition);
+            }
             if (breakpoint.enabled)
-                contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), function() { breakpoint.enabled = false; });
+                contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), setBreakpointEnabled.bind(this, false));
             else
-                contextMenu.appendItem(WebInspector.UIString("Enable Breakpoint"), function() { breakpoint.enabled = true; });
+                contextMenu.appendItem(WebInspector.UIString("Enable Breakpoint"), setBreakpointEnabled.bind(this, true));
         }
         contextMenu.show(event);
     },
@@ -535,12 +542,11 @@ WebInspector.SourceFrame.prototype = {
 
         var breakpoint = this._findBreakpoint(lineNumber);
         if (breakpoint) {
+            breakpoint.remove();
             if (event.shiftKey)
-                breakpoint.enabled = !breakpoint.enabled;
-            else
-                breakpoint.remove();
+                this._setBreakpoint(breakpoint.line, !breakpoint.enabled, breakpoint.condition);
         } else
-            this._setBreakpoint(lineNumber);
+            this._setBreakpoint(lineNumber, true, "");
         event.preventDefault();
     },
 
@@ -775,7 +781,7 @@ WebInspector.SourceFrame.prototype = {
         var sourceID = this._sourceIDForLine(lineNumber);
         if (!sourceID)
             return;
-        WebInspector.panels.scripts.continueToLine(sourceID, lineNumber);
+        WebInspector.debuggerModel.continueToLine(sourceID, lineNumber);
     },
 
     _editLine: function(lineNumber, newContent, cancelEditingCallback)
@@ -823,12 +829,12 @@ WebInspector.SourceFrame.prototype = {
             script.resource.setContent(newContent, revertEditLineCallback);
     },
 
-    _setBreakpoint: function(lineNumber, condition)
+    _setBreakpoint: function(lineNumber, enabled, condition)
     {
         var sourceID = this._sourceIDForLine(lineNumber);
         if (!sourceID)
             return;
-        WebInspector.debuggerModel.setBreakpoint(sourceID, lineNumber, true, condition);
+        WebInspector.debuggerModel.setBreakpoint(sourceID, lineNumber, enabled, condition);
         if (!WebInspector.panels.scripts.breakpointsActivated)
             WebInspector.panels.scripts.toggleBreakpointsClicked();
     },