a70ecb140efe5e6dd978d05601b1c1d021789f09
[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._debuggerPausedDetails = {};
34     this._breakpoints = {};
35     this._scripts = {};
36
37     InspectorBackend.registerDomainDispatcher("Debugger", new WebInspector.DebuggerDispatcher(this));
38 }
39
40 WebInspector.DebuggerModel.Events = {
41     DebuggerWasEnabled: "debugger-was-enabled",
42     DebuggerWasDisabled: "debugger-was-disabled",
43     DebuggerPaused: "debugger-paused",
44     DebuggerResumed: "debugger-resumed",
45     ParsedScriptSource: "parsed-script-source",
46     FailedToParseScriptSource: "failed-to-parse-script-source",
47     BreakpointResolved: "breakpoint-resolved",
48     Reset: "reset"
49 }
50
51 WebInspector.DebuggerModel.prototype = {
52     enableDebugger: function()
53     {
54         DebuggerAgent.enable();
55     },
56
57     disableDebugger: function()
58     {
59         DebuggerAgent.disable();
60     },
61
62     _debuggerWasEnabled: function()
63     {
64         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasEnabled);
65     },
66
67     _debuggerWasDisabled: function()
68     {
69         this._breakpoints = {};
70         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasDisabled);
71     },
72
73     continueToLocation: function(sourceID, lineNumber, columnNumber)
74     {
75         DebuggerAgent.continueToLocation(sourceID, lineNumber, columnNumber);
76     },
77
78     setBreakpoint: function(url, lineNumber, columnNumber, condition, enabled, callback)
79     {
80         // Adjust column if needed.
81         var minColumnNumber = 0;
82         for (var id in this._scripts) {
83             var script = this._scripts[id];
84             if (url === script.sourceURL && lineNumber === script.lineOffset)
85                 minColumnNumber = minColumnNumber ? Math.min(minColumnNumber, script.columnOffset) : script.columnOffset;
86         }
87         columnNumber = Math.max(columnNumber, minColumnNumber);
88
89         function didSetBreakpoint(error, breakpointId, locations)
90         {
91             var breakpoint;
92             if (!error && breakpointId) {
93                 breakpoint = new WebInspector.Breakpoint(breakpointId, url, "", lineNumber, columnNumber, condition, enabled);
94                 breakpoint.locations = locations;
95                 this._breakpoints[breakpointId] = breakpoint;
96             }
97             if (callback)
98                 callback(breakpoint);
99         }
100         DebuggerAgent.setBreakpointByUrl(url, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this));
101     },
102
103     setBreakpointBySourceId: function(sourceID, lineNumber, columnNumber, condition, enabled, callback)
104     {
105         function didSetBreakpoint(error, breakpointId, actualLineNumber, actualColumnNumber)
106         {
107             var breakpoint;
108             if (!error && breakpointId) {
109                 breakpoint = new WebInspector.Breakpoint(breakpointId, "", sourceID, lineNumber, columnNumber, condition, enabled);
110                 breakpoint.addLocation(sourceID, actualLineNumber, actualColumnNumber);
111                 this._breakpoints[breakpointId] = breakpoint;
112             }
113             if (callback)
114                 callback(breakpoint);
115         }
116         DebuggerAgent.setBreakpoint(sourceID, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this));
117     },
118
119     removeBreakpoint: function(breakpointId)
120     {
121         DebuggerAgent.removeBreakpoint(breakpointId);
122         delete this._breakpoints[breakpointId];
123     },
124
125     _breakpointResolved: function(breakpointId, sourceID, lineNumber, columnNumber)
126     {
127         var breakpoint = this._breakpoints[breakpointId];
128         breakpoint.addLocation(sourceID, lineNumber, columnNumber);
129         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, breakpoint);
130     },
131
132     get breakpoints()
133     {
134         return this._breakpoints;
135     },
136
137     reset: function()
138     {
139         this._debuggerPausedDetails = {};
140         for (var id in this._breakpoints) {
141             var breakpoint = this._breakpoints[id];
142             if (!breakpoint.url)
143                 delete this._breakpoints[id];
144             else
145                 breakpoint.locations = [];
146         }
147         this._scripts = {};
148         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.Reset);
149     },
150
151     get scripts()
152     {
153         return this._scripts;
154     },
155
156     scriptForSourceID: function(sourceID)
157     {
158         return this._scripts[sourceID];
159     },
160
161     scriptsForURL: function(url)
162     {
163         return this.queryScripts(function(s) { return s.sourceURL === url; });
164     },
165
166     queryScripts: function(filter)
167     {
168         var scripts = [];
169         for (var sourceID in this._scripts) {
170             var script = this._scripts[sourceID];
171             if (filter(script))
172                 scripts.push(script);
173         }
174         return scripts;
175     },
176
177     editScriptSource: function(sourceID, newSource, callback)
178     {
179         DebuggerAgent.editScriptSource(sourceID, newSource, this._didEditScriptSource.bind(this, sourceID, newSource, callback));
180     },
181
182     _didEditScriptSource: function(sourceID, newSource, callback, error, callFrames)
183     {
184         if (!error) {
185             this._scripts[sourceID].source = newSource;
186             if (callFrames && callFrames.length)
187                 this._debuggerPausedDetails.callFrames = callFrames;
188         }
189         callback(error);
190     },
191
192     get callFrames()
193     {
194         return this._debuggerPausedDetails.callFrames;
195     },
196
197     get debuggerPausedDetails()
198     {
199         return this._debuggerPausedDetails;
200     },
201
202     _pausedScript: function(details)
203     {
204         this._debuggerPausedDetails = details;
205         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details);
206     },
207
208     _resumedScript: function()
209     {
210         this._debuggerPausedDetails = {};
211         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
212     },
213
214     _parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType)
215     {
216         var script = new WebInspector.Script(sourceID, sourceURL, "", lineOffset, columnOffset, length, undefined, undefined, scriptWorldType);
217         this._scripts[sourceID] = script;
218         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, script);
219     },
220
221     _failedToParseScriptSource: function(sourceURL, source, startingLine, errorLine, errorMessage)
222     {
223         var script = new WebInspector.Script(null, sourceURL, source, startingLine, errorLine, errorMessage, undefined);
224         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, script);
225     }
226 }
227
228 WebInspector.DebuggerModel.prototype.__proto__ = WebInspector.Object.prototype;
229
230 WebInspector.DebuggerEventTypes = {
231     JavaScriptPause: 0,
232     JavaScriptBreakpoint: 1,
233     NativeBreakpoint: 2
234 };
235
236 WebInspector.DebuggerDispatcher = function(debuggerModel)
237 {
238     this._debuggerModel = debuggerModel;
239 }
240
241 WebInspector.DebuggerDispatcher.prototype = {
242     paused: function(details)
243     {
244         this._debuggerModel._pausedScript(details);
245     },
246
247     resumed: function()
248     {
249         this._debuggerModel._resumedScript();
250     },
251
252     debuggerWasEnabled: function()
253     {
254         this._debuggerModel._debuggerWasEnabled();
255     },
256
257     debuggerWasDisabled: function()
258     {
259         this._debuggerModel._debuggerWasDisabled();
260     },
261
262     scriptParsed: function(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType)
263     {
264         this._debuggerModel._parsedScriptSource(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType);
265     },
266
267     scriptFailedToParse: function(sourceURL, source, startingLine, errorLine, errorMessage)
268     {
269         this._debuggerModel._failedToParseScriptSource(sourceURL, source, startingLine, errorLine, errorMessage);
270     },
271
272     breakpointResolved: function(breakpointId, sourceID, lineNumber, columnNumber)
273     {
274         this._debuggerModel._breakpointResolved(breakpointId, sourceID, lineNumber, columnNumber);
275     }
276 }