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