| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @constructor |
| 7 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding |
| 8 * @param {!WebInspector.NetworkMapping} networkMapping |
| 9 */ |
| 10 WebInspector.BlackboxManager = function(debuggerWorkspaceBinding, networkMapping
) |
| 11 { |
| 12 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; |
| 13 this._networkMapping = networkMapping; |
| 14 |
| 15 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebI
nspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this
); |
| 16 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebI
nspector.DebuggerModel.Events.GlobalObjectCleared, this._globalObjectCleared, th
is); |
| 17 WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(this.
_patternChanged.bind(this)); |
| 18 WebInspector.moduleSetting("skipContentScripts").addChangeListener(this._pat
ternChanged.bind(this)); |
| 19 |
| 20 /** @type {!Map<string, !Array<!DebuggerAgent.ScriptPosition>>} */ |
| 21 this._scriptIdToPositions = new Map(); |
| 22 /** @type {!Map<string, boolean>} */ |
| 23 this._isBlackboxedURLCache = new Map(); |
| 24 } |
| 25 |
| 26 WebInspector.BlackboxManager.prototype = { |
| 27 |
| 28 /** |
| 29 * @param {function(!WebInspector.Event)} listener |
| 30 * @param {!Object=} thisObject |
| 31 */ |
| 32 addChangeListener: function(listener, thisObject) |
| 33 { |
| 34 WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(l
istener, thisObject); |
| 35 }, |
| 36 |
| 37 /** |
| 38 * @param {function(!WebInspector.Event)} listener |
| 39 * @param {!Object=} thisObject |
| 40 */ |
| 41 removeChangeListener: function(listener, thisObject) |
| 42 { |
| 43 WebInspector.moduleSetting("skipStackFramesPattern").removeChangeListene
r(listener, thisObject); |
| 44 }, |
| 45 |
| 46 /** |
| 47 * @param {!WebInspector.DebuggerModel.Location} location |
| 48 * @return {boolean} |
| 49 */ |
| 50 isBlackboxedRawLocation: function(location) |
| 51 { |
| 52 if (!this._scriptIdToPositions.has(location.scriptId)) |
| 53 return false; |
| 54 var positions = this._scriptIdToPositions.get(location.scriptId); |
| 55 var index = positions.lowerBound(location, comparator); |
| 56 return !!(index % 2); |
| 57 |
| 58 /** |
| 59 * @param {!WebInspector.DebuggerModel.Location} a |
| 60 * @param {!DebuggerAgent.ScriptPosition} b |
| 61 * @return {number} |
| 62 */ |
| 63 function comparator(a, b) |
| 64 { |
| 65 if (a.lineNumber !== b.line) |
| 66 return a.lineNumber - b.line; |
| 67 return a.columnNumber - b.column; |
| 68 } |
| 69 }, |
| 70 |
| 71 /** |
| 72 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 73 * @return {boolean} |
| 74 */ |
| 75 isBlackboxedUISourceCode: function(uiSourceCode) |
| 76 { |
| 77 var projectType = uiSourceCode.project().type(); |
| 78 var isContentScript = projectType === WebInspector.projectTypes.ContentS
cripts; |
| 79 if (isContentScript && WebInspector.moduleSetting("skipContentScripts").
get()) |
| 80 return true; |
| 81 var networkURL = this._networkMapping.networkURL(uiSourceCode); |
| 82 var url = projectType === WebInspector.projectTypes.Formatter ? uiSource
Code.url() : networkURL; |
| 83 return this.isBlackboxedURL(url); |
| 84 }, |
| 85 |
| 86 /** |
| 87 * @param {string} url |
| 88 * @return {boolean} |
| 89 */ |
| 90 isBlackboxedURL: function(url) |
| 91 { |
| 92 if (this._isBlackboxedURLCache.has(url)) |
| 93 return !!this._isBlackboxedURLCache.get(url); |
| 94 var regex = WebInspector.moduleSetting("skipStackFramesPattern").asRegEx
p(); |
| 95 var isBlackboxed = regex && regex.test(url); |
| 96 this._isBlackboxedURLCache.set(url, isBlackboxed); |
| 97 return isBlackboxed; |
| 98 }, |
| 99 |
| 100 /** |
| 101 * @param {!WebInspector.Script} script |
| 102 * @param {?WebInspector.SourceMap} sourceMap |
| 103 * @return {!Promise<undefined>} |
| 104 */ |
| 105 sourceMapLoaded: function(script, sourceMap) |
| 106 { |
| 107 if (!sourceMap) |
| 108 return Promise.resolve(); |
| 109 if (!this._scriptIdToPositions.has(script.scriptId)) |
| 110 return Promise.resolve(); |
| 111 |
| 112 var mappings = sourceMap.mappings().slice(); |
| 113 mappings.sort(mappingComparator); |
| 114 |
| 115 var previousScriptState = this._scriptIdToPositions.get(script.scriptId)
; |
| 116 if (!mappings.length) { |
| 117 if (previousScriptState.length > 0) |
| 118 return this._setScriptState(script, []).then(this._sourceMapLoad
edForTest); |
| 119 } |
| 120 |
| 121 var currentBlackboxed = false; |
| 122 var isBlackboxed = false; |
| 123 var positions = []; |
| 124 // If content in script file begin is not mapped and one or more ranges
are blackboxed then blackbox it. |
| 125 if (mappings[0].lineNumber !== 0 || mappings[0].columnNumber !== 0) { |
| 126 positions.push({ line: 0, column: 0}); |
| 127 currentBlackboxed = true; |
| 128 } |
| 129 for (var mapping of mappings) { |
| 130 if (currentBlackboxed !== this.isBlackboxedURL(mapping.sourceURL)) { |
| 131 positions.push({ line: mapping.lineNumber, column: mapping.colum
nNumber }); |
| 132 currentBlackboxed = !currentBlackboxed; |
| 133 } |
| 134 isBlackboxed = currentBlackboxed || isBlackboxed; |
| 135 } |
| 136 return this._setScriptState(script, !isBlackboxed ? [] : positions).then
(this._sourceMapLoadedForTest); |
| 137 /** |
| 138 * @param {!WebInspector.SourceMap.Entry} a |
| 139 * @param {!WebInspector.SourceMap.Entry} b |
| 140 * @return {number} |
| 141 */ |
| 142 function mappingComparator(a, b) |
| 143 { |
| 144 if (a.lineNumber !== b.lineNumber) |
| 145 return a.lineNumber - b.lineNumber; |
| 146 return a.columnNumber - b.columnNumber; |
| 147 } |
| 148 }, |
| 149 |
| 150 _sourceMapLoadedForTest: function() |
| 151 { |
| 152 // This method is sniffed in tests. |
| 153 }, |
| 154 |
| 155 /** |
| 156 * @param {string} url |
| 157 * @return {boolean} |
| 158 */ |
| 159 canBlackboxURL: function(url) |
| 160 { |
| 161 return !!this._urlToRegExpString(url); |
| 162 }, |
| 163 |
| 164 /** |
| 165 * @param {string} url |
| 166 */ |
| 167 blackboxURL: function(url) |
| 168 { |
| 169 var regexPatterns = WebInspector.moduleSetting("skipStackFramesPattern")
.getAsArray(); |
| 170 var regexValue = this._urlToRegExpString(url); |
| 171 if (!regexValue) |
| 172 return; |
| 173 var found = false; |
| 174 for (var i = 0; i < regexPatterns.length; ++i) { |
| 175 var item = regexPatterns[i]; |
| 176 if (item.pattern === regexValue) { |
| 177 item.disabled = false; |
| 178 found = true; |
| 179 break; |
| 180 } |
| 181 } |
| 182 if (!found) |
| 183 regexPatterns.push({ pattern: regexValue }); |
| 184 WebInspector.moduleSetting("skipStackFramesPattern").setAsArray(regexPat
terns); |
| 185 }, |
| 186 |
| 187 /** |
| 188 * @param {string} url |
| 189 * @param {boolean} isContentScript |
| 190 */ |
| 191 unblackbox: function(url, isContentScript) |
| 192 { |
| 193 if (isContentScript) |
| 194 WebInspector.moduleSetting("skipContentScripts").set(false); |
| 195 |
| 196 var regexPatterns = WebInspector.moduleSetting("skipStackFramesPattern")
.getAsArray(); |
| 197 var regexValue = WebInspector.blackboxManager._urlToRegExpString(url); |
| 198 if (!regexValue) |
| 199 return; |
| 200 regexPatterns = regexPatterns.filter(function(item) { |
| 201 return item.pattern !== regexValue; |
| 202 }); |
| 203 for (var i = 0; i < regexPatterns.length; ++i) { |
| 204 var item = regexPatterns[i]; |
| 205 if (item.disabled) |
| 206 continue; |
| 207 try { |
| 208 var regex = new RegExp(item.pattern); |
| 209 if (regex.test(url)) |
| 210 item.disabled = true; |
| 211 } catch (e) { |
| 212 } |
| 213 } |
| 214 WebInspector.moduleSetting("skipStackFramesPattern").setAsArray(regexPat
terns); |
| 215 }, |
| 216 |
| 217 _patternChanged: function() |
| 218 { |
| 219 this._isBlackboxedURLCache.clear(); |
| 220 |
| 221 var promises = []; |
| 222 for (var debuggerModel of WebInspector.DebuggerModel.instances()) { |
| 223 for (var scriptId in debuggerModel.scripts) { |
| 224 let script = debuggerModel.scripts[scriptId]; |
| 225 promises.push(this._addScript(script) |
| 226 .then(() => this._debuggerWorkspaceBinding.sou
rceMapForScript(script)) |
| 227 .then(loadSourceMap.bind(this, script))); |
| 228 } |
| 229 } |
| 230 Promise.all(promises).then(this._patternChangeFinishedForTests); |
| 231 |
| 232 /** |
| 233 * @param {!WebInspector.Script} script |
| 234 * @param {?WebInspector.SourceMap} sourceMap |
| 235 * @return {!Promise<undefined>} |
| 236 * @this {WebInspector.BlackboxManager} |
| 237 */ |
| 238 function loadSourceMap(script, sourceMap) |
| 239 { |
| 240 return this.sourceMapLoaded(script, sourceMap); |
| 241 } |
| 242 }, |
| 243 |
| 244 _patternChangeFinishedForTests: function() |
| 245 { |
| 246 // This method is sniffed in tests. |
| 247 }, |
| 248 |
| 249 _globalObjectCleared: function() |
| 250 { |
| 251 this._scriptIdToPositions.clear(); |
| 252 this._isBlackboxedURLCache.clear(); |
| 253 }, |
| 254 |
| 255 /** |
| 256 * @param {!WebInspector.Event} event |
| 257 */ |
| 258 _parsedScriptSource: function(event) |
| 259 { |
| 260 var script = /** @type {!WebInspector.Script} */ (event.data); |
| 261 this._addScript(script); |
| 262 }, |
| 263 |
| 264 /** |
| 265 * @param {!WebInspector.Script} script |
| 266 * @return {!Promise<undefined>} |
| 267 */ |
| 268 _addScript: function(script) |
| 269 { |
| 270 var blackboxed = this._isBlackboxedScript(script); |
| 271 return this._setScriptState(script, blackboxed ? [ { line: 0, column: 0
} ] : []); |
| 272 }, |
| 273 |
| 274 /** |
| 275 * @param {!WebInspector.Script} script |
| 276 * @return {boolean} |
| 277 */ |
| 278 _isBlackboxedScript: function(script) |
| 279 { |
| 280 if (script.isContentScript() && WebInspector.moduleSetting("skipContentS
cripts").get()) |
| 281 return true; |
| 282 return this.isBlackboxedURL(script.sourceURL); |
| 283 }, |
| 284 |
| 285 /** |
| 286 * @param {!WebInspector.Script} script |
| 287 * @param {!Array<!DebuggerAgent.ScriptPosition>} positions |
| 288 * @return {!Promise<undefined>} |
| 289 */ |
| 290 _setScriptState: function(script, positions) |
| 291 { |
| 292 if (this._scriptIdToPositions.has(script.scriptId)) { |
| 293 var hasChanged = false; |
| 294 var previousScriptState = this._scriptIdToPositions.get(script.scrip
tId); |
| 295 hasChanged = previousScriptState.length !== positions.length; |
| 296 for (var i = 0; !hasChanged && i < positions.length; ++i) |
| 297 hasChanged = positions[i].line !== previousScriptState[i].line |
| positions[i].column !== previousScriptState[i].column; |
| 298 if (!hasChanged) |
| 299 return Promise.resolve(); |
| 300 } else { |
| 301 if (positions.length === 0) |
| 302 return Promise.resolve().then(updateState.bind(this, false)); |
| 303 } |
| 304 |
| 305 return script.setBlackboxedRanges(positions).then(updateState.bind(this)
); |
| 306 |
| 307 /** |
| 308 * @param {boolean} success |
| 309 * @this {WebInspector.BlackboxManager} |
| 310 */ |
| 311 function updateState(success) |
| 312 { |
| 313 if (success) |
| 314 this._scriptIdToPositions.set(script.scriptId, positions); |
| 315 else if (!this._scriptIdToPositions.has(script.scriptId)) |
| 316 this._scriptIdToPositions.set(script.scriptId, []); |
| 317 } |
| 318 }, |
| 319 |
| 320 /** |
| 321 * @param {string} url |
| 322 * @return {string} |
| 323 */ |
| 324 _urlToRegExpString: function(url) |
| 325 { |
| 326 var parsedURL = new WebInspector.ParsedURL(url); |
| 327 if (parsedURL.isAboutBlank() || parsedURL.isDataURL()) |
| 328 return ""; |
| 329 if (!parsedURL.isValid) |
| 330 return "^" + url.escapeForRegExp() + "$"; |
| 331 var name = parsedURL.lastPathComponent; |
| 332 if (name) |
| 333 name = "/" + name; |
| 334 else if (parsedURL.folderPathComponents) |
| 335 name = parsedURL.folderPathComponents + "/"; |
| 336 if (!name) |
| 337 name = parsedURL.host; |
| 338 if (!name) |
| 339 return ""; |
| 340 var scheme = parsedURL.scheme; |
| 341 var prefix = ""; |
| 342 if (scheme && scheme !== "http" && scheme !== "https") { |
| 343 prefix = "^" + scheme + "://"; |
| 344 if (scheme === "chrome-extension") |
| 345 prefix += parsedURL.host + "\\b"; |
| 346 prefix += ".*"; |
| 347 } |
| 348 return prefix + name.escapeForRegExp() + (url.endsWith(name) ? "$" : "\\
b"); |
| 349 } |
| 350 } |
| 351 |
| 352 /** @type {!WebInspector.BlackboxManager} */ |
| 353 WebInspector.blackboxManager; |
| OLD | NEW |