2011-01-17 Pavel Feldman <pfeldman@chromium.org>
[WebKit-https.git] / Source / WebCore / inspector / front-end / DebuggerModel.js
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 WebInspector.DebuggerModel = function()
32 {
33     this._paused = false;
34     this._breakpoints = {};
35     this._sourceIDAndLineToBreakpointId = {};
36     this._scripts = {};
37
38     InspectorBackend.registerDomainDispatcher("Debugger", new WebInspector.DebuggerDispatcher(this));
39 }
40
41 WebInspector.DebuggerModel.Events = {
42     DebuggerPaused: "debugger-paused",
43     DebuggerResumed: "debugger-resumed",
44     ParsedScriptSource: "parsed-script-source",
45     FailedToParseScriptSource: "failed-to-parse-script-source",
46     BreakpointAdded: "breakpoint-added",
47     BreakpointRemoved: "breakpoint-removed"
48 }
49
50 WebInspector.DebuggerModel.prototype = {
51     continueToLine: function(sourceID, lineNumber)
52     {
53         function didSetBreakpoint(breakpointId, actualLineNumber)
54         {
55             if (!breakpointId)
56                 return;
57             if (this.findBreakpoint(sourceID, actualLineNumber)) {
58                 InspectorBackend.removeBreakpoint(breakpointId);
59                 return;
60             }
61             if ("_continueToLineBreakpointId" in this)
62                 InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId);
63             this._continueToLineBreakpointId = breakpointId;
64         }
65         InspectorBackend.setBreakpoint(sourceID, lineNumber, "", true, didSetBreakpoint.bind(this));
66         if (this._paused)
67             InspectorBackend.resume();
68     },
69
70     setBreakpoint: function(sourceID, lineNumber, enabled, condition)
71     {
72         function didSetBreakpoint(breakpointId, actualLineNumber)
73         {
74             if (breakpointId)
75                 this._breakpointSetOnBackend(breakpointId, sourceID, actualLineNumber, condition, enabled, lineNumber, false);
76         }
77         InspectorBackend.setBreakpoint(sourceID, lineNumber, condition, enabled, didSetBreakpoint.bind(this));
78     },
79
80     removeBreakpoint: function(breakpointId)
81     {
82         InspectorBackend.removeBreakpoint(breakpointId);
83         var breakpoint = this._breakpoints[breakpointId];
84         delete this._breakpoints[breakpointId];
85         delete this._sourceIDAndLineToBreakpointId[this._encodeSourceIDAndLine(breakpoint.sourceID, breakpoint.line)];
86         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointRemoved, breakpointId);
87     },
88
89     _breakpointSetOnBackend: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, restored)
90     {
91         var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber);
92         if (sourceIDAndLine in this._sourceIDAndLineToBreakpointId) {
93             InspectorBackend.removeBreakpoint(breakpointId);
94             return;
95         }
96
97         var url = this._scripts[sourceID].sourceURL;
98         var breakpoint = new WebInspector.Breakpoint(this, breakpointId, sourceID, url, lineNumber, enabled, condition);
99         breakpoint.restored = restored;
100         breakpoint.originalLineNumber = originalLineNumber;
101         this._breakpoints[breakpointId] = breakpoint;
102         this._sourceIDAndLineToBreakpointId[sourceIDAndLine] = breakpointId;
103         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint);
104     },
105
106     queryBreakpoints: function(filter)
107     {
108         var breakpoints = [];
109         for (var id in this._breakpoints) {
110            var breakpoint = this._breakpoints[id];
111            if (filter(breakpoint))
112                breakpoints.push(breakpoint);
113         }
114         return breakpoints;
115     },
116
117     findBreakpoint: function(sourceID, lineNumber)
118     {
119         var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber);
120         var breakpointId = this._sourceIDAndLineToBreakpointId[sourceIDAndLine];
121         return this._breakpoints[breakpointId];
122     },
123
124     _encodeSourceIDAndLine: function(sourceID, lineNumber)
125     {
126         return sourceID + ":" + lineNumber;
127     },
128
129     reset: function()
130     {
131         this._paused = false;
132         this._breakpoints = {};
133         delete this._oneTimeBreakpoint;
134         this._sourceIDAndLineToBreakpointId = {};
135         this._scripts = {};
136     },
137
138     scriptForSourceID: function(sourceID)
139     {
140         return this._scripts[sourceID];
141     },
142
143     scriptsForURL: function(url)
144     {
145         return this.queryScripts(function(s) { return s.sourceURL === url; });
146     },
147
148     queryScripts: function(filter)
149     {
150         var scripts = [];
151         for (var sourceID in this._scripts) {
152             var script = this._scripts[sourceID];
153             if (filter(script))
154                 scripts.push(script);
155         }
156         return scripts;
157     },
158
159     _pausedScript: function(details)
160     {
161         this._paused = true;
162         if ("_continueToLineBreakpointId" in this) {
163             InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId);
164             delete this._continueToLineBreakpointId;
165         }
166         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details);
167
168         if (details.eventType === WebInspector.DebuggerEventTypes.JavaScriptPause || details.eventType === WebInspector.DebuggerEventTypes.NativeBreakpoint)
169             return;
170
171         var breakpoint = this.findBreakpoint(details.callFrames[0].sourceID, details.callFrames[0].line);
172         if (!breakpoint)
173             return;
174         breakpoint.hit = true;
175         this._lastHitBreakpoint = breakpoint;
176     },
177
178     _resumedScript: function()
179     {
180         this._paused = false;
181         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
182
183         if (!this._lastHitBreakpoint)
184             return;
185         this._lastHitBreakpoint.hit = false;
186         delete this._lastHitBreakpoint;
187     },
188
189     _parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, scriptWorldType)
190     {
191         var script = new WebInspector.Script(sourceID, sourceURL, "", lineOffset, columnOffset, undefined, undefined, scriptWorldType);
192         this._scripts[sourceID] = script;
193         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, sourceID);
194     },
195
196     _failedToParseScriptSource: function(sourceURL, source, startingLine, errorLine, errorMessage)
197     {
198         var script = new WebInspector.Script(null, sourceURL, source, startingLine, errorLine, errorMessage, undefined);
199         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, script);
200     }
201 }
202
203 WebInspector.DebuggerModel.prototype.__proto__ = WebInspector.Object.prototype;
204
205 WebInspector.DebuggerEventTypes = {
206     JavaScriptPause: 0,
207     JavaScriptBreakpoint: 1,
208     NativeBreakpoint: 2
209 };
210
211 WebInspector.DebuggerDispatcher = function(debuggerModel)
212 {
213     this._debuggerModel = debuggerModel;
214 }
215
216 WebInspector.DebuggerDispatcher.prototype = {
217     pausedScript: function(details)
218     {
219         this._debuggerModel._pausedScript(details);
220     },
221
222     resumedScript: function()
223     {
224         this._debuggerModel._resumedScript();
225     },
226
227     debuggerWasEnabled: function()
228     {
229         WebInspector.panels.scripts.debuggerWasEnabled();
230     },
231
232     debuggerWasDisabled: function()
233     {
234         WebInspector.panels.scripts.debuggerWasDisabled();
235     },
236
237     parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, scriptWorldType)
238     {
239         this._debuggerModel._parsedScriptSource(sourceID, sourceURL, lineOffset, columnOffset, scriptWorldType);
240     },
241
242     failedToParseScriptSource: function(sourceURL, source, startingLine, errorLine, errorMessage)
243     {
244         this._debuggerModel._failedToParseScriptSource(sourceURL, source, startingLine, errorLine, errorMessage);
245     },
246
247     breakpointResolved: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber)
248     {
249         this._debuggerModel._breakpointSetOnBackend(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, true);
250     },
251
252     didCreateWorker: function()
253     {
254         var workersPane = WebInspector.panels.scripts.sidebarPanes.workers;
255         workersPane.addWorker.apply(workersPane, arguments);
256     },
257
258     didDestroyWorker: function()
259     {
260         var workersPane = WebInspector.panels.scripts.sidebarPanes.workers;
261         workersPane.removeWorker.apply(workersPane, arguments);
262     }
263 }