initial import
[vuplus_webkit] / Source / WebCore / inspector / front-end / BreakpointManager.js
1 /*
2  * Copyright (C) 2011 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 /**
32  * @constructor
33  */
34 WebInspector.BreakpointManager = function(breakpointStorage, breakpointAddedDelegate, breakpointRemovedDelegate, debuggerModel)
35 {
36     this._breakpointStorage = breakpointStorage;
37     this._breakpointAddedDelegate = breakpointAddedDelegate;
38     this._breakpointRemovedDelegate = breakpointRemovedDelegate;
39     this._breakpointsByUILocation = {};
40
41     this._debuggerModel = debuggerModel;
42     this._breakpointsByDebuggerId = {};
43     this._debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this);
44
45     var breakpoints = this._breakpointStorage.get();
46     for (var i = 0; i < breakpoints.length; ++i) {
47         var breakpoint = WebInspector.Breakpoint.deserialize(breakpoints[i]);
48         if (!this._breakpoint(breakpoint.uiSourceCodeId, breakpoint.lineNumber))
49             this._addBreakpointToUI(breakpoint);
50     }
51 }
52
53 WebInspector.BreakpointManager.prototype = {
54     uiSourceCodeAdded: function(uiSourceCode)
55     {
56         var breakpoints = this._breakpoints(uiSourceCode.id);
57         for (var lineNumber in breakpoints) {
58             var breakpoint = breakpoints[lineNumber];
59             breakpoint.uiSourceCode = uiSourceCode;
60             this._materializeBreakpoint(breakpoint);
61             if (breakpoint._debuggerLocation)
62                 this._breakpointDebuggerLocationChanged(breakpoint, breakpoint._debuggerLocation);
63         }
64     },
65
66     breakpointsForUISourceCode: function(uiSourceCode)
67     {
68         return this._breakpoints(uiSourceCode.id);
69     },
70
71     setBreakpoint: function(uiSourceCode, lineNumber, condition, enabled)
72     {
73         if (this._breakpoint(uiSourceCode.id, lineNumber))
74             return;
75
76         var persistent = !!uiSourceCode.url;
77         var breakpoint = new WebInspector.Breakpoint(uiSourceCode.id, lineNumber, condition, enabled, persistent);
78         breakpoint.uiSourceCode = uiSourceCode;
79         this._addBreakpointToUI(breakpoint);
80         this._materializeBreakpoint(breakpoint);
81     },
82
83     removeBreakpoint: function(uiSourceCode, lineNumber)
84     {
85         var breakpoint = this._breakpoint(uiSourceCode.id, lineNumber);
86         if (!breakpoint)
87             return;
88         this._deleteBreakpointFromUI(breakpoint);
89         this._removeBreakpointFromDebugger(breakpoint);
90     },
91
92     _materializeBreakpoint: function(breakpoint)
93     {
94         if (!breakpoint.enabled || breakpoint._materialized)
95             return;
96
97         breakpoint._materialized = true;
98         var rawLocation = breakpoint.uiSourceCode.rawSourceCode.uiLocationToRawLocation(breakpoint.lineNumber, 0);
99         this._setBreakpointInDebugger(breakpoint, rawLocation);
100     },
101
102     _breakpointDebuggerLocationChanged: function(breakpoint)
103     {
104         if (!breakpoint.uiSourceCode)
105             return;
106         var uiLocation = breakpoint.uiSourceCode.rawSourceCode.rawLocationToUILocation(breakpoint._debuggerLocation);
107         if (uiLocation.lineNumber === breakpoint.lineNumber)
108             return;
109
110         if (!this._moveBreakpointInUI(breakpoint, uiLocation.lineNumber))
111             this._removeBreakpointFromDebugger(breakpoint);
112     },
113
114     _addBreakpointToUI: function(breakpoint)
115     {
116         console.assert(!this._breakpoint(breakpoint.uiSourceCodeId, breakpoint.lineNumber));
117         this._breakpoints(breakpoint.uiSourceCodeId)[breakpoint.lineNumber] = breakpoint;
118         this._saveBreakpoints();
119         this._breakpointAddedDelegate(breakpoint);
120     },
121
122     _deleteBreakpointFromUI: function(breakpoint)
123     {
124         console.assert(this._breakpoint(breakpoint.uiSourceCodeId, breakpoint.lineNumber) === breakpoint);
125         delete this._breakpoints(breakpoint.uiSourceCodeId)[breakpoint.lineNumber];
126         this._saveBreakpoints();
127         this._breakpointRemovedDelegate(breakpoint);
128     },
129
130     _moveBreakpointInUI: function(breakpoint, lineNumber)
131     {
132         this._deleteBreakpointFromUI(breakpoint);
133         if (this._breakpoint(breakpoint.uiSourceCodeId, lineNumber))
134             return false;
135         breakpoint.lineNumber = lineNumber;
136         this._addBreakpointToUI(breakpoint);
137         return true;
138     },
139
140     _breakpoints: function(uiSourceCodeId)
141     {
142         if (!this._breakpointsByUILocation[uiSourceCodeId])
143             this._breakpointsByUILocation[uiSourceCodeId] = {};
144         return this._breakpointsByUILocation[uiSourceCodeId];
145     },
146
147     _breakpoint: function(uiSourceCodeId, lineNumber)
148     {
149         return this._breakpoints(uiSourceCodeId)[lineNumber];
150     },
151
152     _forEachBreakpoint: function(handler)
153     {
154         for (var uiSourceCodeId in this._breakpointsByUILocation) {
155             var breakpoints = this._breakpointsByUILocation[uiSourceCodeId];
156             for (var lineNumber in breakpoints)
157                 handler(breakpoints[lineNumber]);
158         }
159     },
160
161     _setBreakpointInDebugger: function(breakpoint, rawLocation)
162     {
163         function didSetBreakpoint(breakpointId, locations)
164         {
165             if (breakpoint === this._breakpoint(breakpoint.uiSourceCodeId, breakpoint.lineNumber)) {
166                 if (!breakpointId) {
167                     this._deleteBreakpointFromUI(breakpoint);
168                     return;
169                 }
170             } else {
171                 if (breakpointId)
172                     this._debuggerModel.removeBreakpoint(breakpointId);
173                 return;
174             }
175
176             this._breakpointsByDebuggerId[breakpointId] = breakpoint;
177             breakpoint._debuggerId = breakpointId;
178             breakpoint._debuggerLocation = locations[0];
179             if (breakpoint._debuggerLocation)
180                 this._breakpointDebuggerLocationChanged(breakpoint);
181         }
182         this._debuggerModel.setBreakpointByScriptLocation(rawLocation, breakpoint.condition, didSetBreakpoint.bind(this));
183     },
184
185     _removeBreakpointFromDebugger: function(breakpoint)
186     {
187         if (!("_debuggerId" in breakpoint))
188             return;
189         this._debuggerModel.removeBreakpoint(breakpoint._debuggerId);
190         delete this._breakpointsByDebuggerId[breakpoint._debuggerId];
191         delete breakpoint._debuggerId;
192         delete breakpoint._debuggerLocation;
193     },
194
195     _breakpointResolved: function(event)
196     {
197         var breakpoint = this._breakpointsByDebuggerId[event.data.breakpointId];
198         breakpoint._debuggerLocation = event.data.location;
199         this._breakpointDebuggerLocationChanged(breakpoint);
200     },
201
202     _saveBreakpoints: function()
203     {
204         var serializedBreakpoints = [];
205         function serializePersistent(breakpoint)
206         {
207             if (breakpoint.persistent)
208                 serializedBreakpoints.push(breakpoint.serialize());
209         }
210         this._forEachBreakpoint(serializePersistent.bind(this));
211         this._breakpointStorage.set(serializedBreakpoints);
212     },
213
214     reset: function()
215     {
216         function resetBreakpoint(breakpoint)
217         {
218             this._removeBreakpointFromDebugger(breakpoint);
219             delete breakpoint._materialized;
220         }
221         this._forEachBreakpoint(resetBreakpoint.bind(this));
222     },
223
224     debuggerReset: function()
225     {
226         function resetOrDeleteBreakpoint(breakpoint)
227         {
228             if (breakpoint.persistent) {
229                 delete breakpoint.uiSourceCode;
230                 delete breakpoint._debuggerLocation;
231             } else {
232                 this._deleteBreakpointFromUI(breakpoint);
233                 delete this._breakpointsByDebuggerId[breakpoint._debuggerId];
234             }
235         }
236         this._forEachBreakpoint(resetOrDeleteBreakpoint.bind(this));
237
238         for (var id in this._breakpointsByUILocation) {
239             var empty = true;
240             for (var lineNumber in this._breakpointsByUILocation[id]) {
241                 empty = false;
242                 break;
243             }
244             if (empty)
245                 delete this._breakpointsByUILocation[id];
246         }
247     }
248 }
249
250 /**
251  * @constructor
252  */
253 WebInspector.Breakpoint = function(uiSourceCodeId, lineNumber, condition, enabled, persistent)
254 {
255     this.uiSourceCodeId = uiSourceCodeId;
256     this.lineNumber = lineNumber;
257     this.condition = condition;
258     this.enabled = enabled;
259     this.persistent = persistent;
260 }
261
262 WebInspector.Breakpoint.prototype = {
263     serialize: function()
264     {
265         var serializedBreakpoint = {};
266         serializedBreakpoint.sourceFileId = this.uiSourceCodeId;
267         serializedBreakpoint.lineNumber = this.lineNumber;
268         serializedBreakpoint.condition = this.condition;
269         serializedBreakpoint.enabled = this.enabled;
270         return serializedBreakpoint;
271     }
272 }
273
274 WebInspector.Breakpoint.deserialize = function(serializedBreakpoint)
275 {
276     return new WebInspector.Breakpoint(
277             serializedBreakpoint.sourceFileId,
278             serializedBreakpoint.lineNumber,
279             serializedBreakpoint.condition,
280             serializedBreakpoint.enabled,
281             true);
282 }