| Index: third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js | 
| diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js b/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..8751939299018e35c1135a7eff5f9af728764685 | 
| --- /dev/null | 
| +++ b/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js | 
| @@ -0,0 +1,353 @@ | 
| +// Copyright 2014 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +/** | 
| + * @constructor | 
| + * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | 
| + * @param {!WebInspector.NetworkMapping} networkMapping | 
| + */ | 
| +WebInspector.BlackboxManager = function(debuggerWorkspaceBinding, networkMapping) | 
| +{ | 
| +    this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | 
| +    this._networkMapping = networkMapping; | 
| + | 
| +    WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this); | 
| +    WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._globalObjectCleared, this); | 
| +    WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(this._patternChanged.bind(this)); | 
| +    WebInspector.moduleSetting("skipContentScripts").addChangeListener(this._patternChanged.bind(this)); | 
| + | 
| +    /** @type {!Map<string, !Array<!DebuggerAgent.ScriptPosition>>} */ | 
| +    this._scriptIdToPositions = new Map(); | 
| +    /** @type {!Map<string, boolean>} */ | 
| +    this._isBlackboxedURLCache = new Map(); | 
| +} | 
| + | 
| +WebInspector.BlackboxManager.prototype = { | 
| + | 
| +    /** | 
| +     * @param {function(!WebInspector.Event)} listener | 
| +     * @param {!Object=} thisObject | 
| +     */ | 
| +    addChangeListener: function(listener, thisObject) | 
| +    { | 
| +        WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(listener, thisObject); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {function(!WebInspector.Event)} listener | 
| +     * @param {!Object=} thisObject | 
| +     */ | 
| +    removeChangeListener: function(listener, thisObject) | 
| +    { | 
| +        WebInspector.moduleSetting("skipStackFramesPattern").removeChangeListener(listener, thisObject); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.DebuggerModel.Location} location | 
| +     * @return {boolean} | 
| +     */ | 
| +    isBlackboxedRawLocation: function(location) | 
| +    { | 
| +        if (!this._scriptIdToPositions.has(location.scriptId)) | 
| +            return false; | 
| +        var positions = this._scriptIdToPositions.get(location.scriptId); | 
| +        var index = positions.lowerBound(location, comparator); | 
| +        return !!(index % 2); | 
| + | 
| +        /** | 
| +         * @param {!WebInspector.DebuggerModel.Location} a | 
| +         * @param {!DebuggerAgent.ScriptPosition} b | 
| +         * @return {number} | 
| +         */ | 
| +        function comparator(a, b) | 
| +        { | 
| +            if (a.lineNumber !== b.line) | 
| +                return a.lineNumber - b.line; | 
| +            return a.columnNumber - b.column; | 
| +        } | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.UISourceCode} uiSourceCode | 
| +     * @return {boolean} | 
| +     */ | 
| +    isBlackboxedUISourceCode: function(uiSourceCode) | 
| +    { | 
| +        var projectType = uiSourceCode.project().type(); | 
| +        var isContentScript = projectType === WebInspector.projectTypes.ContentScripts; | 
| +        if (isContentScript && WebInspector.moduleSetting("skipContentScripts").get()) | 
| +            return true; | 
| +        var networkURL = this._networkMapping.networkURL(uiSourceCode); | 
| +        var url = projectType === WebInspector.projectTypes.Formatter ? uiSourceCode.url() : networkURL; | 
| +        return this.isBlackboxedURL(url); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {string} url | 
| +     * @return {boolean} | 
| +     */ | 
| +    isBlackboxedURL: function(url) | 
| +    { | 
| +        if (this._isBlackboxedURLCache.has(url)) | 
| +            return !!this._isBlackboxedURLCache.get(url); | 
| +        var regex = WebInspector.moduleSetting("skipStackFramesPattern").asRegExp(); | 
| +        var isBlackboxed = regex && regex.test(url); | 
| +        this._isBlackboxedURLCache.set(url, isBlackboxed); | 
| +        return isBlackboxed; | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.Script} script | 
| +     * @param {?WebInspector.SourceMap} sourceMap | 
| +     * @return {!Promise<undefined>} | 
| +     */ | 
| +    sourceMapLoaded: function(script, sourceMap) | 
| +    { | 
| +        if (!sourceMap) | 
| +            return Promise.resolve(); | 
| +        if (!this._scriptIdToPositions.has(script.scriptId)) | 
| +            return Promise.resolve(); | 
| + | 
| +        var mappings = sourceMap.mappings().slice(); | 
| +        mappings.sort(mappingComparator); | 
| + | 
| +        var previousScriptState = this._scriptIdToPositions.get(script.scriptId); | 
| +        if (!mappings.length) { | 
| +            if (previousScriptState.length > 0) | 
| +                return this._setScriptState(script, []).then(this._sourceMapLoadedForTest); | 
| +        } | 
| + | 
| +        var currentBlackboxed = false; | 
| +        var isBlackboxed = false; | 
| +        var positions = []; | 
| +        // If content in script file begin is not mapped and one or more ranges are blackboxed then blackbox it. | 
| +        if (mappings[0].lineNumber !== 0 || mappings[0].columnNumber !== 0) { | 
| +            positions.push({ line: 0, column: 0}); | 
| +            currentBlackboxed = true; | 
| +        } | 
| +        for (var mapping of mappings) { | 
| +            if (currentBlackboxed !== this.isBlackboxedURL(mapping.sourceURL)) { | 
| +                positions.push({ line: mapping.lineNumber, column: mapping.columnNumber }); | 
| +                currentBlackboxed = !currentBlackboxed; | 
| +            } | 
| +            isBlackboxed = currentBlackboxed || isBlackboxed; | 
| +        } | 
| +        return this._setScriptState(script, !isBlackboxed ? [] : positions).then(this._sourceMapLoadedForTest); | 
| +        /** | 
| +         * @param {!WebInspector.SourceMap.Entry} a | 
| +         * @param {!WebInspector.SourceMap.Entry} b | 
| +         * @return {number} | 
| +         */ | 
| +        function mappingComparator(a, b) | 
| +        { | 
| +            if (a.lineNumber !== b.lineNumber) | 
| +                return a.lineNumber - b.lineNumber; | 
| +            return a.columnNumber - b.columnNumber; | 
| +        } | 
| +    }, | 
| + | 
| +    _sourceMapLoadedForTest: function() | 
| +    { | 
| +        // This method is sniffed in tests. | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {string} url | 
| +     * @return {boolean} | 
| +     */ | 
| +    canBlackboxURL: function(url) | 
| +    { | 
| +        return !!this._urlToRegExpString(url); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {string} url | 
| +     */ | 
| +    blackboxURL: function(url) | 
| +    { | 
| +        var regexPatterns = WebInspector.moduleSetting("skipStackFramesPattern").getAsArray(); | 
| +        var regexValue = this._urlToRegExpString(url); | 
| +        if (!regexValue) | 
| +            return; | 
| +        var found = false; | 
| +        for (var i = 0; i < regexPatterns.length; ++i) { | 
| +            var item = regexPatterns[i]; | 
| +            if (item.pattern === regexValue) { | 
| +                item.disabled = false; | 
| +                found = true; | 
| +                break; | 
| +            } | 
| +        } | 
| +        if (!found) | 
| +            regexPatterns.push({ pattern: regexValue }); | 
| +        WebInspector.moduleSetting("skipStackFramesPattern").setAsArray(regexPatterns); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {string} url | 
| +     * @param {boolean} isContentScript | 
| +     */ | 
| +    unblackbox: function(url, isContentScript) | 
| +    { | 
| +        if (isContentScript) | 
| +            WebInspector.moduleSetting("skipContentScripts").set(false); | 
| + | 
| +        var regexPatterns = WebInspector.moduleSetting("skipStackFramesPattern").getAsArray(); | 
| +        var regexValue = WebInspector.blackboxManager._urlToRegExpString(url); | 
| +        if (!regexValue) | 
| +            return; | 
| +        regexPatterns = regexPatterns.filter(function(item) { | 
| +            return item.pattern !== regexValue; | 
| +        }); | 
| +        for (var i = 0; i < regexPatterns.length; ++i) { | 
| +            var item = regexPatterns[i]; | 
| +            if (item.disabled) | 
| +                continue; | 
| +            try { | 
| +                var regex = new RegExp(item.pattern); | 
| +                if (regex.test(url)) | 
| +                    item.disabled = true; | 
| +            } catch (e) { | 
| +            } | 
| +        } | 
| +        WebInspector.moduleSetting("skipStackFramesPattern").setAsArray(regexPatterns); | 
| +    }, | 
| + | 
| +    _patternChanged: function() | 
| +    { | 
| +        this._isBlackboxedURLCache.clear(); | 
| + | 
| +        var promises = []; | 
| +        for (var debuggerModel of WebInspector.DebuggerModel.instances()) { | 
| +            for (var scriptId in debuggerModel.scripts) { | 
| +                let script = debuggerModel.scripts[scriptId]; | 
| +                promises.push(this._addScript(script) | 
| +                                  .then(() => this._debuggerWorkspaceBinding.sourceMapForScript(script)) | 
| +                                  .then(loadSourceMap.bind(this, script))); | 
| +            } | 
| +        } | 
| +        Promise.all(promises).then(this._patternChangeFinishedForTests); | 
| + | 
| +        /** | 
| +         * @param {!WebInspector.Script} script | 
| +         * @param {?WebInspector.SourceMap} sourceMap | 
| +         * @return {!Promise<undefined>} | 
| +         * @this {WebInspector.BlackboxManager} | 
| +         */ | 
| +        function loadSourceMap(script, sourceMap) | 
| +        { | 
| +            return this.sourceMapLoaded(script, sourceMap); | 
| +        } | 
| +    }, | 
| + | 
| +    _patternChangeFinishedForTests: function() | 
| +    { | 
| +        // This method is sniffed in tests. | 
| +    }, | 
| + | 
| +    _globalObjectCleared: function() | 
| +    { | 
| +        this._scriptIdToPositions.clear(); | 
| +        this._isBlackboxedURLCache.clear(); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.Event} event | 
| +     */ | 
| +    _parsedScriptSource: function(event) | 
| +    { | 
| +        var script = /** @type {!WebInspector.Script} */ (event.data); | 
| +        this._addScript(script); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.Script} script | 
| +     * @return {!Promise<undefined>} | 
| +     */ | 
| +    _addScript: function(script) | 
| +    { | 
| +        var blackboxed = this._isBlackboxedScript(script); | 
| +        return this._setScriptState(script, blackboxed ? [ { line: 0, column: 0 } ] : []); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.Script} script | 
| +     * @return {boolean} | 
| +     */ | 
| +    _isBlackboxedScript: function(script) | 
| +    { | 
| +        if (script.isContentScript() && WebInspector.moduleSetting("skipContentScripts").get()) | 
| +            return true; | 
| +        return this.isBlackboxedURL(script.sourceURL); | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {!WebInspector.Script} script | 
| +     * @param {!Array<!DebuggerAgent.ScriptPosition>} positions | 
| +     * @return {!Promise<undefined>} | 
| +     */ | 
| +    _setScriptState: function(script, positions) | 
| +    { | 
| +        if (this._scriptIdToPositions.has(script.scriptId)) { | 
| +            var hasChanged = false; | 
| +            var previousScriptState = this._scriptIdToPositions.get(script.scriptId); | 
| +            hasChanged = previousScriptState.length !== positions.length; | 
| +            for (var i = 0; !hasChanged && i < positions.length; ++i) | 
| +                hasChanged = positions[i].line !== previousScriptState[i].line || positions[i].column !== previousScriptState[i].column; | 
| +            if (!hasChanged) | 
| +                return Promise.resolve(); | 
| +        } else { | 
| +            if (positions.length === 0) | 
| +                return Promise.resolve().then(updateState.bind(this, false)); | 
| +        } | 
| + | 
| +        return script.setBlackboxedRanges(positions).then(updateState.bind(this)); | 
| + | 
| +        /** | 
| +         * @param {boolean} success | 
| +         * @this {WebInspector.BlackboxManager} | 
| +         */ | 
| +        function updateState(success) | 
| +        { | 
| +            if (success) | 
| +                this._scriptIdToPositions.set(script.scriptId, positions); | 
| +            else if (!this._scriptIdToPositions.has(script.scriptId)) | 
| +                this._scriptIdToPositions.set(script.scriptId, []); | 
| +        } | 
| +    }, | 
| + | 
| +    /** | 
| +     * @param {string} url | 
| +     * @return {string} | 
| +     */ | 
| +    _urlToRegExpString: function(url) | 
| +    { | 
| +        var parsedURL = new WebInspector.ParsedURL(url); | 
| +        if (parsedURL.isAboutBlank() || parsedURL.isDataURL()) | 
| +            return ""; | 
| +        if (!parsedURL.isValid) | 
| +            return "^" + url.escapeForRegExp() + "$"; | 
| +        var name = parsedURL.lastPathComponent; | 
| +        if (name) | 
| +            name = "/" + name; | 
| +        else if (parsedURL.folderPathComponents) | 
| +            name = parsedURL.folderPathComponents + "/"; | 
| +        if (!name) | 
| +            name = parsedURL.host; | 
| +        if (!name) | 
| +            return ""; | 
| +        var scheme = parsedURL.scheme; | 
| +        var prefix = ""; | 
| +        if (scheme && scheme !== "http" && scheme !== "https") { | 
| +            prefix = "^" + scheme + "://"; | 
| +            if (scheme === "chrome-extension") | 
| +                prefix += parsedURL.host + "\\b"; | 
| +            prefix += ".*"; | 
| +        } | 
| +        return prefix + name.escapeForRegExp() + (url.endsWith(name) ? "$" : "\\b"); | 
| +    } | 
| +} | 
| + | 
| +/** @type {!WebInspector.BlackboxManager} */ | 
| +WebInspector.blackboxManager; | 
|  |