| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 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 * @implements {WebInspector.ScriptSourceMapping} | |
| 34 * @param {!WebInspector.DebuggerModel} debuggerModel | |
| 35 * @param {!WebInspector.Workspace} workspace | |
| 36 * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding | |
| 37 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
| 38 */ | |
| 39 WebInspector.CompilerScriptMapping = function(debuggerModel, workspace, networkW
orkspaceBinding, debuggerWorkspaceBinding) | |
| 40 { | |
| 41 this._target = debuggerModel.target(); | |
| 42 this._debuggerModel = debuggerModel; | |
| 43 this._workspace = workspace; | |
| 44 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA
dded, this._uiSourceCodeAddedToWorkspace, this); | |
| 45 this._networkWorkspaceBinding = networkWorkspaceBinding; | |
| 46 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | |
| 47 | |
| 48 /** @type {!Object.<string, !WebInspector.SourceMap>} */ | |
| 49 this._sourceMapForSourceMapURL = {}; | |
| 50 /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>} */ | |
| 51 this._pendingSourceMapLoadingCallbacks = {}; | |
| 52 /** @type {!Object.<string, !WebInspector.SourceMap>} */ | |
| 53 this._sourceMapForScriptId = {}; | |
| 54 /** @type {!Map.<!WebInspector.SourceMap, !WebInspector.Script>} */ | |
| 55 this._scriptForSourceMap = new Map(); | |
| 56 /** @type {!StringMap.<!WebInspector.SourceMap>} */ | |
| 57 this._sourceMapForURL = new StringMap(); | |
| 58 debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjec
tCleared, this._debuggerReset, this); | |
| 59 } | |
| 60 | |
| 61 WebInspector.CompilerScriptMapping.prototype = { | |
| 62 /** | |
| 63 * @param {!WebInspector.RawLocation} rawLocation | |
| 64 * @return {?WebInspector.UILocation} | |
| 65 */ | |
| 66 rawLocationToUILocation: function(rawLocation) | |
| 67 { | |
| 68 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Locat
ion} */ (rawLocation); | |
| 69 var sourceMap = this._sourceMapForScriptId[debuggerModelLocation.scriptI
d]; | |
| 70 if (!sourceMap) | |
| 71 return null; | |
| 72 var lineNumber = debuggerModelLocation.lineNumber; | |
| 73 var columnNumber = debuggerModelLocation.columnNumber || 0; | |
| 74 var entry = sourceMap.findEntry(lineNumber, columnNumber); | |
| 75 if (!entry || entry.length === 2) | |
| 76 return null; | |
| 77 var url = /** @type {string} */ (entry[2]); | |
| 78 var uiSourceCode = this._workspace.uiSourceCodeForURL(url); | |
| 79 if (!uiSourceCode) | |
| 80 return null; | |
| 81 return uiSourceCode.uiLocation(/** @type {number} */ (entry[3]), /** @ty
pe {number} */ (entry[4])); | |
| 82 }, | |
| 83 | |
| 84 /** | |
| 85 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 86 * @param {number} lineNumber | |
| 87 * @param {number} columnNumber | |
| 88 * @return {?WebInspector.DebuggerModel.Location} | |
| 89 */ | |
| 90 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) | |
| 91 { | |
| 92 if (!uiSourceCode.url) | |
| 93 return null; | |
| 94 var sourceMap = this._sourceMapForURL.get(uiSourceCode.url); | |
| 95 if (!sourceMap) | |
| 96 return null; | |
| 97 var script = /** @type {!WebInspector.Script} */ (this._scriptForSourceM
ap.get(sourceMap)); | |
| 98 console.assert(script); | |
| 99 var mappingSearchLinesCount = 5; | |
| 100 // We do not require precise (breakpoint) location but limit the number
of lines to search or mapping. | |
| 101 var entry = sourceMap.findEntryReversed(uiSourceCode.url, lineNumber, ma
ppingSearchLinesCount); | |
| 102 if (!entry) | |
| 103 return null; | |
| 104 return this._debuggerModel.createRawLocation(script, /** @type {number}
*/ (entry[0]), /** @type {number} */ (entry[1])); | |
| 105 }, | |
| 106 | |
| 107 /** | |
| 108 * @param {!WebInspector.Script} script | |
| 109 */ | |
| 110 addScript: function(script) | |
| 111 { | |
| 112 this._debuggerWorkspaceBinding.pushSourceMapping(script, this); | |
| 113 script.addEventListener(WebInspector.Script.Events.SourceMapURLAdded, th
is._sourceMapURLAdded.bind(this)); | |
| 114 this._processScript(script); | |
| 115 }, | |
| 116 | |
| 117 /** | |
| 118 * @param {!WebInspector.Event} event | |
| 119 */ | |
| 120 _sourceMapURLAdded: function(event) | |
| 121 { | |
| 122 var script = /** @type {!WebInspector.Script} */ (event.target); | |
| 123 this._processScript(script); | |
| 124 }, | |
| 125 | |
| 126 /** | |
| 127 * @param {!WebInspector.Script} script | |
| 128 */ | |
| 129 _processScript: function(script) | |
| 130 { | |
| 131 this.loadSourceMapForScript(script, sourceMapLoaded.bind(this)); | |
| 132 | |
| 133 /** | |
| 134 * @param {?WebInspector.SourceMap} sourceMap | |
| 135 * @this {WebInspector.CompilerScriptMapping} | |
| 136 */ | |
| 137 function sourceMapLoaded(sourceMap) | |
| 138 { | |
| 139 if (!sourceMap) | |
| 140 return; | |
| 141 | |
| 142 if (this._scriptForSourceMap.get(sourceMap)) { | |
| 143 this._sourceMapForScriptId[script.scriptId] = sourceMap; | |
| 144 this._debuggerWorkspaceBinding.updateLocations(script); | |
| 145 return; | |
| 146 } | |
| 147 | |
| 148 this._sourceMapForScriptId[script.scriptId] = sourceMap; | |
| 149 this._scriptForSourceMap.put(sourceMap, script); | |
| 150 | |
| 151 var sourceURLs = sourceMap.sources(); | |
| 152 for (var i = 0; i < sourceURLs.length; ++i) { | |
| 153 var sourceURL = sourceURLs[i]; | |
| 154 if (this._sourceMapForURL.get(sourceURL)) | |
| 155 continue; | |
| 156 this._sourceMapForURL.put(sourceURL, sourceMap); | |
| 157 if (!this._workspace.hasMappingForURL(sourceURL) && !this._works
pace.uiSourceCodeForURL(sourceURL)) { | |
| 158 var contentProvider = sourceMap.sourceContentProvider(source
URL, WebInspector.resourceTypes.Script); | |
| 159 this._networkWorkspaceBinding.addFileForURL(sourceURL, conte
ntProvider, script.isContentScript()); | |
| 160 } | |
| 161 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL)
; | |
| 162 if (uiSourceCode) | |
| 163 this._bindUISourceCode(uiSourceCode); | |
| 164 else | |
| 165 WebInspector.console.error(WebInspector.UIString("Failed to
locate workspace file mapped to URL %s from source map %s", sourceURL, sourceMap
.url())); | |
| 166 } | |
| 167 this._debuggerWorkspaceBinding.updateLocations(script); | |
| 168 } | |
| 169 }, | |
| 170 | |
| 171 /** | |
| 172 * @return {boolean} | |
| 173 */ | |
| 174 isIdentity: function() | |
| 175 { | |
| 176 return false; | |
| 177 }, | |
| 178 | |
| 179 /** | |
| 180 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 181 * @param {number} lineNumber | |
| 182 * @return {boolean} | |
| 183 */ | |
| 184 uiLineHasMapping: function(uiSourceCode, lineNumber) | |
| 185 { | |
| 186 if (!uiSourceCode.url) | |
| 187 return true; | |
| 188 var sourceMap = this._sourceMapForURL.get(uiSourceCode.url); | |
| 189 if (!sourceMap) | |
| 190 return true; | |
| 191 return !!sourceMap.findEntryReversed(uiSourceCode.url, lineNumber, 0); | |
| 192 }, | |
| 193 | |
| 194 /** | |
| 195 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 196 */ | |
| 197 _bindUISourceCode: function(uiSourceCode) | |
| 198 { | |
| 199 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, this); | |
| 200 }, | |
| 201 | |
| 202 /** | |
| 203 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 204 */ | |
| 205 _unbindUISourceCode: function(uiSourceCode) | |
| 206 { | |
| 207 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, null); | |
| 208 }, | |
| 209 | |
| 210 /** | |
| 211 * @param {!WebInspector.Event} event | |
| 212 */ | |
| 213 _uiSourceCodeAddedToWorkspace: function(event) | |
| 214 { | |
| 215 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
| 216 if (!uiSourceCode.url || !this._sourceMapForURL.get(uiSourceCode.url)) | |
| 217 return; | |
| 218 this._bindUISourceCode(uiSourceCode); | |
| 219 }, | |
| 220 | |
| 221 /** | |
| 222 * @param {!WebInspector.Script} script | |
| 223 * @param {function(?WebInspector.SourceMap)} callback | |
| 224 */ | |
| 225 loadSourceMapForScript: function(script, callback) | |
| 226 { | |
| 227 // script.sourceURL can be a random string, but is generally an absolute
path -> complete it to inspected page url for | |
| 228 // relative links. | |
| 229 if (!script.sourceMapURL) { | |
| 230 callback(null); | |
| 231 return; | |
| 232 } | |
| 233 var scriptURL = WebInspector.ParsedURL.completeURL(script.target().resou
rceTreeModel.inspectedPageURL(), script.sourceURL); | |
| 234 if (!scriptURL) { | |
| 235 callback(null); | |
| 236 return; | |
| 237 } | |
| 238 var sourceMapURL = WebInspector.ParsedURL.completeURL(scriptURL, script.
sourceMapURL); | |
| 239 if (!sourceMapURL) { | |
| 240 callback(null); | |
| 241 return; | |
| 242 } | |
| 243 | |
| 244 var sourceMap = this._sourceMapForSourceMapURL[sourceMapURL]; | |
| 245 if (sourceMap) { | |
| 246 callback(sourceMap); | |
| 247 return; | |
| 248 } | |
| 249 | |
| 250 var pendingCallbacks = this._pendingSourceMapLoadingCallbacks[sourceMapU
RL]; | |
| 251 if (pendingCallbacks) { | |
| 252 pendingCallbacks.push(callback); | |
| 253 return; | |
| 254 } | |
| 255 | |
| 256 pendingCallbacks = [callback]; | |
| 257 this._pendingSourceMapLoadingCallbacks[sourceMapURL] = pendingCallbacks; | |
| 258 | |
| 259 WebInspector.SourceMap.load(sourceMapURL, scriptURL, sourceMapLoaded.bin
d(this)); | |
| 260 | |
| 261 /** | |
| 262 * @param {?WebInspector.SourceMap} sourceMap | |
| 263 * @this {WebInspector.CompilerScriptMapping} | |
| 264 */ | |
| 265 function sourceMapLoaded(sourceMap) | |
| 266 { | |
| 267 var url = /** @type {string} */ (sourceMapURL); | |
| 268 var callbacks = this._pendingSourceMapLoadingCallbacks[url]; | |
| 269 delete this._pendingSourceMapLoadingCallbacks[url]; | |
| 270 if (!callbacks) | |
| 271 return; | |
| 272 if (sourceMap) | |
| 273 this._sourceMapForSourceMapURL[url] = sourceMap; | |
| 274 for (var i = 0; i < callbacks.length; ++i) | |
| 275 callbacks[i](sourceMap); | |
| 276 } | |
| 277 }, | |
| 278 | |
| 279 _debuggerReset: function() | |
| 280 { | |
| 281 /** | |
| 282 * @param {string} sourceURL | |
| 283 * @this {WebInspector.CompilerScriptMapping} | |
| 284 */ | |
| 285 function unbindUISourceCodeForURL(sourceURL) | |
| 286 { | |
| 287 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL); | |
| 288 if (!uiSourceCode) | |
| 289 return; | |
| 290 this._unbindUISourceCode(uiSourceCode); | |
| 291 } | |
| 292 | |
| 293 this._sourceMapForURL.keys().forEach(unbindUISourceCodeForURL.bind(this)
); | |
| 294 | |
| 295 this._sourceMapForSourceMapURL = {}; | |
| 296 this._pendingSourceMapLoadingCallbacks = {}; | |
| 297 this._sourceMapForScriptId = {}; | |
| 298 this._scriptForSourceMap.clear(); | |
| 299 this._sourceMapForURL.clear(); | |
| 300 }, | |
| 301 | |
| 302 dispose: function() | |
| 303 { | |
| 304 this._workspace.removeEventListener(WebInspector.Workspace.Events.UISour
ceCodeAdded, this._uiSourceCodeAddedToWorkspace, this); | |
| 305 } | |
| 306 } | |
| OLD | NEW |