Home | History | Annotate | Download | only in front_end
      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 /**
     32  * @constructor
     33  * @extends {WebInspector.Object}
     34  */
     35 WebInspector.DebuggerModel = function()
     36 {
     37     InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerDispatcher(this));
     38 
     39     this._debuggerPausedDetails = null;
     40     /**
     41      * @type {Object.<string, WebInspector.Script>}
     42      */
     43     this._scripts = {};
     44     /** @type {!Object.<!string, !Array.<!WebInspector.Script>>} */
     45     this._scriptsBySourceURL = {};
     46 
     47     this._canSetScriptSource = false;
     48     this._breakpointsActive = true;
     49 
     50     WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.DebuggerModel.PauseOnExceptionsState.DontPauseOnExceptions);
     51     WebInspector.settings.pauseOnExceptionStateString.addChangeListener(this._pauseOnExceptionStateChanged, this);
     52 
     53     this.enableDebugger();
     54 
     55     WebInspector.DebuggerModel.applySkipStackFrameSettings();
     56 }
     57 
     58 // Keep these in sync with WebCore::ScriptDebugServer
     59 WebInspector.DebuggerModel.PauseOnExceptionsState = {
     60     DontPauseOnExceptions : "none",
     61     PauseOnAllExceptions : "all",
     62     PauseOnUncaughtExceptions: "uncaught"
     63 };
     64 
     65 /**
     66  * @constructor
     67  * @implements {WebInspector.RawLocation}
     68  * @param {string} scriptId
     69  * @param {number} lineNumber
     70  * @param {number} columnNumber
     71  */
     72 WebInspector.DebuggerModel.Location = function(scriptId, lineNumber, columnNumber)
     73 {
     74     this.scriptId = scriptId;
     75     this.lineNumber = lineNumber;
     76     this.columnNumber = columnNumber;
     77 }
     78 
     79 WebInspector.DebuggerModel.Events = {
     80     DebuggerWasEnabled: "DebuggerWasEnabled",
     81     DebuggerWasDisabled: "DebuggerWasDisabled",
     82     DebuggerPaused: "DebuggerPaused",
     83     DebuggerResumed: "DebuggerResumed",
     84     ParsedScriptSource: "ParsedScriptSource",
     85     FailedToParseScriptSource: "FailedToParseScriptSource",
     86     BreakpointResolved: "BreakpointResolved",
     87     GlobalObjectCleared: "GlobalObjectCleared",
     88     CallFrameSelected: "CallFrameSelected",
     89     ExecutionLineChanged: "ExecutionLineChanged",
     90     ConsoleCommandEvaluatedInSelectedCallFrame: "ConsoleCommandEvaluatedInSelectedCallFrame",
     91     BreakpointsActiveStateChanged: "BreakpointsActiveStateChanged"
     92 }
     93 
     94 WebInspector.DebuggerModel.BreakReason = {
     95     DOM: "DOM",
     96     EventListener: "EventListener",
     97     XHR: "XHR",
     98     Exception: "exception",
     99     Assert: "assert",
    100     CSPViolation: "CSPViolation",
    101     DebugCommand: "debugCommand"
    102 }
    103 
    104 WebInspector.DebuggerModel.prototype = {
    105     /**
    106      * @return {boolean}
    107      */
    108     debuggerEnabled: function()
    109     {
    110         return !!this._debuggerEnabled;
    111     },
    112 
    113     enableDebugger: function()
    114     {
    115         if (this._debuggerEnabled)
    116             return;
    117 
    118         function callback(error, result)
    119         {
    120             this._canSetScriptSource = result;
    121         }
    122         DebuggerAgent.canSetScriptSource(callback.bind(this));
    123         DebuggerAgent.enable(this._debuggerWasEnabled.bind(this));
    124     },
    125 
    126     disableDebugger: function()
    127     {
    128         if (!this._debuggerEnabled)
    129             return;
    130 
    131         DebuggerAgent.disable(this._debuggerWasDisabled.bind(this));
    132     },
    133 
    134     /**
    135      * @return {boolean}
    136      */
    137     canSetScriptSource: function()
    138     {
    139         return this._canSetScriptSource;
    140     },
    141 
    142     _debuggerWasEnabled: function()
    143     {
    144         this._debuggerEnabled = true;
    145         this._pauseOnExceptionStateChanged();
    146         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasEnabled);
    147     },
    148 
    149     _pauseOnExceptionStateChanged: function()
    150     {
    151         DebuggerAgent.setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
    152     },
    153 
    154     _debuggerWasDisabled: function()
    155     {
    156         this._debuggerEnabled = false;
    157         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasDisabled);
    158     },
    159 
    160     /**
    161      * @param {WebInspector.DebuggerModel.Location} rawLocation
    162      */
    163     continueToLocation: function(rawLocation)
    164     {
    165         DebuggerAgent.continueToLocation(rawLocation);
    166     },
    167 
    168     /**
    169      * @param {WebInspector.DebuggerModel.Location} rawLocation
    170      * @param {string} condition
    171      * @param {function(?DebuggerAgent.BreakpointId, Array.<WebInspector.DebuggerModel.Location>):void=} callback
    172      */
    173     setBreakpointByScriptLocation: function(rawLocation, condition, callback)
    174     {
    175         var script = this.scriptForId(rawLocation.scriptId);
    176         if (script.sourceURL)
    177             this.setBreakpointByURL(script.sourceURL, rawLocation.lineNumber, rawLocation.columnNumber, condition, callback);
    178         else
    179             this.setBreakpointBySourceId(rawLocation, condition, callback);
    180     },
    181 
    182     /**
    183      * @param {string} url
    184      * @param {number} lineNumber
    185      * @param {number=} columnNumber
    186      * @param {string=} condition
    187      * @param {function(?DebuggerAgent.BreakpointId, Array.<WebInspector.DebuggerModel.Location>)=} callback
    188      */
    189     setBreakpointByURL: function(url, lineNumber, columnNumber, condition, callback)
    190     {
    191         // Adjust column if needed.
    192         var minColumnNumber = 0;
    193         var scripts = this._scriptsBySourceURL[url] || [];
    194         for (var i = 0, l = scripts.length; i < l; ++i) {
    195             var script = scripts[i];
    196             if (lineNumber === script.lineOffset)
    197                 minColumnNumber = minColumnNumber ? Math.min(minColumnNumber, script.columnOffset) : script.columnOffset;
    198         }
    199         columnNumber = Math.max(columnNumber, minColumnNumber);
    200 
    201         /**
    202          * @this {WebInspector.DebuggerModel}
    203          * @param {?Protocol.Error} error
    204          * @param {DebuggerAgent.BreakpointId} breakpointId
    205          * @param {Array.<DebuggerAgent.Location>} locations
    206          */
    207         function didSetBreakpoint(error, breakpointId, locations)
    208         {
    209             if (callback) {
    210                 var rawLocations = /** @type {Array.<WebInspector.DebuggerModel.Location>} */ (locations);
    211                 callback(error ? null : breakpointId, rawLocations);
    212             }
    213         }
    214         DebuggerAgent.setBreakpointByUrl(lineNumber, url, undefined, columnNumber, condition, undefined, didSetBreakpoint.bind(this));
    215         WebInspector.userMetrics.ScriptsBreakpointSet.record();
    216     },
    217 
    218     /**
    219      * @param {WebInspector.DebuggerModel.Location} rawLocation
    220      * @param {string} condition
    221      * @param {function(?DebuggerAgent.BreakpointId, Array.<WebInspector.DebuggerModel.Location>)=} callback
    222      */
    223     setBreakpointBySourceId: function(rawLocation, condition, callback)
    224     {
    225         /**
    226          * @this {WebInspector.DebuggerModel}
    227          * @param {?Protocol.Error} error
    228          * @param {DebuggerAgent.BreakpointId} breakpointId
    229          * @param {DebuggerAgent.Location} actualLocation
    230          */
    231         function didSetBreakpoint(error, breakpointId, actualLocation)
    232         {
    233             if (callback) {
    234                 var rawLocation = /** @type {WebInspector.DebuggerModel.Location} */ (actualLocation);
    235                 callback(error ? null : breakpointId, [rawLocation]);
    236             }
    237         }
    238         DebuggerAgent.setBreakpoint(rawLocation, condition, didSetBreakpoint.bind(this));
    239         WebInspector.userMetrics.ScriptsBreakpointSet.record();
    240     },
    241 
    242     /**
    243      * @param {DebuggerAgent.BreakpointId} breakpointId
    244      * @param {function(?Protocol.Error)=} callback
    245      */
    246     removeBreakpoint: function(breakpointId, callback)
    247     {
    248         DebuggerAgent.removeBreakpoint(breakpointId, callback);
    249     },
    250 
    251     /**
    252      * @param {DebuggerAgent.BreakpointId} breakpointId
    253      * @param {DebuggerAgent.Location} location
    254      */
    255     _breakpointResolved: function(breakpointId, location)
    256     {
    257         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, {breakpointId: breakpointId, location: location});
    258     },
    259 
    260     _globalObjectCleared: function()
    261     {
    262         this._setDebuggerPausedDetails(null);
    263         this._reset();
    264         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.GlobalObjectCleared);
    265     },
    266 
    267     _reset: function()
    268     {
    269         this._scripts = {};
    270         this._scriptsBySourceURL = {};
    271     },
    272 
    273     /**
    274      * @return {Object.<string, WebInspector.Script>}
    275      */
    276     get scripts()
    277     {
    278         return this._scripts;
    279     },
    280 
    281     /**
    282      * @param {DebuggerAgent.ScriptId} scriptId
    283      * @return {WebInspector.Script}
    284      */
    285     scriptForId: function(scriptId)
    286     {
    287         return this._scripts[scriptId] || null;
    288     },
    289 
    290     /**
    291      * @return {!Array.<!WebInspector.Script>}
    292      */
    293     scriptsForSourceURL: function(sourceURL)
    294     {
    295         if (!sourceURL)
    296             return [];
    297         return this._scriptsBySourceURL[sourceURL] || [];
    298     },
    299 
    300     /**
    301      * @param {DebuggerAgent.ScriptId} scriptId
    302      * @param {string} newSource
    303      * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=)} callback
    304      */
    305     setScriptSource: function(scriptId, newSource, callback)
    306     {
    307         this._scripts[scriptId].editSource(newSource, this._didEditScriptSource.bind(this, scriptId, newSource, callback));
    308     },
    309 
    310     /**
    311      * @param {DebuggerAgent.ScriptId} scriptId
    312      * @param {string} newSource
    313      * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=)} callback
    314      * @param {?Protocol.Error} error
    315      * @param {DebuggerAgent.SetScriptSourceError=} errorData
    316      * @param {Array.<DebuggerAgent.CallFrame>=} callFrames
    317      */
    318     _didEditScriptSource: function(scriptId, newSource, callback, error, errorData, callFrames)
    319     {
    320         callback(error, errorData);
    321         if (!error && callFrames && callFrames.length)
    322             this._pausedScript(callFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData, this._debuggerPausedDetails.breakpointIds);
    323     },
    324 
    325     /**
    326      * @return {Array.<DebuggerAgent.CallFrame>}
    327      */
    328     get callFrames()
    329     {
    330         return this._debuggerPausedDetails ? this._debuggerPausedDetails.callFrames : null;
    331     },
    332 
    333     /**
    334      * @return {?WebInspector.DebuggerPausedDetails}
    335      */
    336     debuggerPausedDetails: function()
    337     {
    338         return this._debuggerPausedDetails;
    339     },
    340 
    341     /**
    342      * @param {?WebInspector.DebuggerPausedDetails} debuggerPausedDetails
    343      */
    344     _setDebuggerPausedDetails: function(debuggerPausedDetails)
    345     {
    346         if (this._debuggerPausedDetails)
    347             this._debuggerPausedDetails.dispose();
    348         this._debuggerPausedDetails = debuggerPausedDetails;
    349         if (this._debuggerPausedDetails)
    350             this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPausedDetails);
    351         if (debuggerPausedDetails) {
    352             this.setSelectedCallFrame(debuggerPausedDetails.callFrames[0]);
    353             DebuggerAgent.setOverlayMessage(WebInspector.UIString("Paused in debugger"));
    354         } else {
    355             this.setSelectedCallFrame(null);
    356             DebuggerAgent.setOverlayMessage();
    357         }
    358     },
    359 
    360     /**
    361      * @param {Array.<DebuggerAgent.CallFrame>} callFrames
    362      * @param {string} reason
    363      * @param {Object|undefined} auxData
    364      * @param {Array.<string>} breakpointIds
    365      */
    366     _pausedScript: function(callFrames, reason, auxData, breakpointIds)
    367     {
    368         this._setDebuggerPausedDetails(new WebInspector.DebuggerPausedDetails(this, callFrames, reason, auxData, breakpointIds));
    369     },
    370 
    371     _resumedScript: function()
    372     {
    373         this._setDebuggerPausedDetails(null);
    374         if (this._executionLineLiveLocation)
    375             this._executionLineLiveLocation.dispose();
    376         this._executionLineLiveLocation = null;
    377         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
    378     },
    379 
    380     /**
    381      * @param {DebuggerAgent.ScriptId} scriptId
    382      * @param {string} sourceURL
    383      * @param {number} startLine
    384      * @param {number} startColumn
    385      * @param {number} endLine
    386      * @param {number} endColumn
    387      * @param {boolean} isContentScript
    388      * @param {string=} sourceMapURL
    389      * @param {boolean=} hasSourceURL
    390      */
    391     _parsedScriptSource: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
    392     {
    393         var script = new WebInspector.Script(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL);
    394         this._registerScript(script);
    395         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, script);
    396     },
    397 
    398     /**
    399      * @param {WebInspector.Script} script
    400      */
    401     _registerScript: function(script)
    402     {
    403         this._scripts[script.scriptId] = script;
    404         if (script.isAnonymousScript())
    405             return;
    406 
    407         var scripts = this._scriptsBySourceURL[script.sourceURL];
    408         if (!scripts) {
    409             scripts = [];
    410             this._scriptsBySourceURL[script.sourceURL] = scripts;
    411         }
    412         scripts.push(script);
    413     },
    414 
    415     /**
    416      * @param {WebInspector.Script} script
    417      * @param {number} lineNumber
    418      * @param {number} columnNumber
    419      * @return {WebInspector.DebuggerModel.Location}
    420      */
    421     createRawLocation: function(script, lineNumber, columnNumber)
    422     {
    423         if (script.sourceURL)
    424             return this.createRawLocationByURL(script.sourceURL, lineNumber, columnNumber)
    425         return new WebInspector.DebuggerModel.Location(script.scriptId, lineNumber, columnNumber);
    426     },
    427 
    428     /**
    429      * @param {string} sourceURL
    430      * @param {number} lineNumber
    431      * @param {number} columnNumber
    432      * @return {WebInspector.DebuggerModel.Location}
    433      */
    434     createRawLocationByURL: function(sourceURL, lineNumber, columnNumber)
    435     {
    436         var closestScript = null;
    437         var scripts = this._scriptsBySourceURL[sourceURL] || [];
    438         for (var i = 0, l = scripts.length; i < l; ++i) {
    439             var script = scripts[i];
    440             if (!closestScript)
    441                 closestScript = script;
    442             if (script.lineOffset > lineNumber || (script.lineOffset === lineNumber && script.columnOffset > columnNumber))
    443                 continue;
    444             if (script.endLine < lineNumber || (script.endLine === lineNumber && script.endColumn <= columnNumber))
    445                 continue;
    446             closestScript = script;
    447             break;
    448         }
    449         return closestScript ? new WebInspector.DebuggerModel.Location(closestScript.scriptId, lineNumber, columnNumber) : null;
    450     },
    451 
    452     /**
    453      * @return {boolean}
    454      */
    455     isPaused: function()
    456     {
    457         return !!this.debuggerPausedDetails();
    458     },
    459 
    460     /**
    461      * @param {?WebInspector.DebuggerModel.CallFrame} callFrame
    462      */
    463     setSelectedCallFrame: function(callFrame)
    464     {
    465         if (this._executionLineLiveLocation)
    466             this._executionLineLiveLocation.dispose();
    467         delete this._executionLineLiveLocation;
    468 
    469         this._selectedCallFrame = callFrame;
    470         if (!this._selectedCallFrame)
    471             return;
    472 
    473         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.CallFrameSelected, callFrame);
    474 
    475         function updateExecutionLine(uiLocation)
    476         {
    477             this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ExecutionLineChanged, uiLocation);
    478         }
    479         this._executionLineLiveLocation = callFrame.script.createLiveLocation(callFrame.location, updateExecutionLine.bind(this));
    480     },
    481 
    482     /**
    483      * @return {?WebInspector.DebuggerModel.CallFrame}
    484      */
    485     selectedCallFrame: function()
    486     {
    487         return this._selectedCallFrame;
    488     },
    489 
    490     /**
    491      * @param {string} code
    492      * @param {string} objectGroup
    493      * @param {boolean} includeCommandLineAPI
    494      * @param {boolean} doNotPauseOnExceptionsAndMuteConsole
    495      * @param {boolean} returnByValue
    496      * @param {boolean} generatePreview
    497      * @param {function(?WebInspector.RemoteObject, boolean, RuntimeAgent.RemoteObject=)} callback
    498      */
    499     evaluateOnSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
    500     {
    501         /**
    502          * @param {?RuntimeAgent.RemoteObject} result
    503          * @param {boolean=} wasThrown
    504          */
    505         function didEvaluate(result, wasThrown)
    506         {
    507             if (returnByValue)
    508                 callback(null, !!wasThrown, wasThrown ? null : result);
    509             else
    510                 callback(WebInspector.RemoteObject.fromPayload(result), !!wasThrown);
    511 
    512             if (objectGroup === "console")
    513                 this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame);
    514         }
    515 
    516         this.selectedCallFrame().evaluate(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, didEvaluate.bind(this));
    517     },
    518 
    519     /**
    520      * @param {function(Object)} callback
    521      */
    522     getSelectedCallFrameVariables: function(callback)
    523     {
    524         var result = { this: true };
    525 
    526         var selectedCallFrame = this._selectedCallFrame;
    527         if (!selectedCallFrame)
    528             callback(result);
    529 
    530         var pendingRequests = 0;
    531 
    532         function propertiesCollected(properties)
    533         {
    534             for (var i = 0; properties && i < properties.length; ++i)
    535                 result[properties[i].name] = true;
    536             if (--pendingRequests == 0)
    537                 callback(result);
    538         }
    539 
    540         for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
    541             var scope = selectedCallFrame.scopeChain[i];
    542             var object = WebInspector.RemoteObject.fromPayload(scope.object);
    543             pendingRequests++;
    544             object.getAllProperties(false, propertiesCollected);
    545         }
    546     },
    547 
    548     /**
    549      * @param {boolean} active
    550      */
    551     setBreakpointsActive: function(active)
    552     {
    553         if (this._breakpointsActive === active)
    554             return;
    555         this._breakpointsActive = active;
    556         DebuggerAgent.setBreakpointsActive(active);
    557         this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, active);
    558     },
    559 
    560     /**
    561      * @return {boolean}
    562      */
    563     breakpointsActive: function()
    564     {
    565         return this._breakpointsActive;
    566     },
    567 
    568     /**
    569      * @param {WebInspector.DebuggerModel.Location} rawLocation
    570      * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
    571      * @return {WebInspector.Script.Location}
    572      */
    573     createLiveLocation: function(rawLocation, updateDelegate)
    574     {
    575         var script = this._scripts[rawLocation.scriptId];
    576         return script.createLiveLocation(rawLocation, updateDelegate);
    577     },
    578 
    579     /**
    580      * @param {WebInspector.DebuggerModel.Location} rawLocation
    581      * @return {?WebInspector.UILocation}
    582      */
    583     rawLocationToUILocation: function(rawLocation)
    584     {
    585         var script = this._scripts[rawLocation.scriptId];
    586         if (!script)
    587             return null;
    588         return script.rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
    589     },
    590 
    591     /**
    592      * Handles notification from JavaScript VM about updated stack (liveedit or frame restart action).
    593      * @this {WebInspector.DebuggerModel}
    594      * @param {Array.<DebuggerAgent.CallFrame>=} newCallFrames
    595      * @param {Object=} details
    596      */
    597     callStackModified: function(newCallFrames, details)
    598     {
    599         // FIXME: declare this property in protocol and in JavaScript.
    600         if (details && details["stack_update_needs_step_in"])
    601             DebuggerAgent.stepInto();
    602         else {
    603             if (newCallFrames && newCallFrames.length)
    604                 this._pausedScript(newCallFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData, this._debuggerPausedDetails.breakpointIds);
    605 
    606         }
    607     },
    608 
    609     __proto__: WebInspector.Object.prototype
    610 }
    611 
    612 WebInspector.DebuggerModel.applySkipStackFrameSettings = function()
    613 {
    614     if (!WebInspector.experimentsSettings.frameworksDebuggingSupport.isEnabled())
    615         return;
    616     var settings = WebInspector.settings;
    617     var patternParameter = settings.skipStackFramesSwitch.get() ? settings.skipStackFramesPattern.get() : undefined;
    618     DebuggerAgent.skipStackFrames(patternParameter);
    619 }
    620 
    621 WebInspector.DebuggerEventTypes = {
    622     JavaScriptPause: 0,
    623     JavaScriptBreakpoint: 1,
    624     NativeBreakpoint: 2
    625 };
    626 
    627 /**
    628  * @constructor
    629  * @implements {DebuggerAgent.Dispatcher}
    630  * @param {WebInspector.DebuggerModel} debuggerModel
    631  */
    632 WebInspector.DebuggerDispatcher = function(debuggerModel)
    633 {
    634     this._debuggerModel = debuggerModel;
    635 }
    636 
    637 WebInspector.DebuggerDispatcher.prototype = {
    638     /**
    639      * @param {Array.<DebuggerAgent.CallFrame>} callFrames
    640      * @param {string} reason
    641      * @param {Object=} auxData
    642      * @param {Array.<string>=} breakpointIds
    643      */
    644     paused: function(callFrames, reason, auxData, breakpointIds)
    645     {
    646         this._debuggerModel._pausedScript(callFrames, reason, auxData, breakpointIds || []);
    647     },
    648 
    649     resumed: function()
    650     {
    651         this._debuggerModel._resumedScript();
    652     },
    653 
    654     globalObjectCleared: function()
    655     {
    656         this._debuggerModel._globalObjectCleared();
    657     },
    658 
    659     /**
    660      * @param {DebuggerAgent.ScriptId} scriptId
    661      * @param {string} sourceURL
    662      * @param {number} startLine
    663      * @param {number} startColumn
    664      * @param {number} endLine
    665      * @param {number} endColumn
    666      * @param {boolean=} isContentScript
    667      * @param {string=} sourceMapURL
    668      * @param {boolean=} hasSourceURL
    669      */
    670     scriptParsed: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
    671     {
    672         this._debuggerModel._parsedScriptSource(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, !!isContentScript, sourceMapURL, hasSourceURL);
    673     },
    674 
    675     /**
    676      * @param {string} sourceURL
    677      * @param {string} source
    678      * @param {number} startingLine
    679      * @param {number} errorLine
    680      * @param {string} errorMessage
    681      */
    682     scriptFailedToParse: function(sourceURL, source, startingLine, errorLine, errorMessage)
    683     {
    684     },
    685 
    686     /**
    687     * @param {DebuggerAgent.BreakpointId} breakpointId
    688     * @param {DebuggerAgent.Location} location
    689      */
    690     breakpointResolved: function(breakpointId, location)
    691     {
    692         this._debuggerModel._breakpointResolved(breakpointId, location);
    693     }
    694 }
    695 
    696 /**
    697  * @constructor
    698  * @param {WebInspector.Script} script
    699  * @param {DebuggerAgent.CallFrame} payload
    700  */
    701 WebInspector.DebuggerModel.CallFrame = function(script, payload)
    702 {
    703     this._script = script;
    704     this._payload = payload;
    705     this._locations = [];
    706 }
    707 
    708 WebInspector.DebuggerModel.CallFrame.prototype = {
    709     /**
    710      * @return {WebInspector.Script}
    711      */
    712     get script()
    713     {
    714         return this._script;
    715     },
    716 
    717     /**
    718      * @return {string}
    719      */
    720     get type()
    721     {
    722         return this._payload.type;
    723     },
    724 
    725     /**
    726      * @return {string}
    727      */
    728     get id()
    729     {
    730         return this._payload.callFrameId;
    731     },
    732 
    733     /**
    734      * @return {Array.<DebuggerAgent.Scope>}
    735      */
    736     get scopeChain()
    737     {
    738         return this._payload.scopeChain;
    739     },
    740 
    741     /**
    742      * @return {RuntimeAgent.RemoteObject}
    743      */
    744     get this()
    745     {
    746         return this._payload.this;
    747     },
    748 
    749     /**
    750      * @return {string}
    751      */
    752     get functionName()
    753     {
    754         return this._payload.functionName;
    755     },
    756 
    757     /**
    758      * @return {WebInspector.DebuggerModel.Location}
    759      */
    760     get location()
    761     {
    762         var rawLocation = /** @type {WebInspector.DebuggerModel.Location} */ (this._payload.location);
    763         return rawLocation;
    764     },
    765 
    766     /**
    767      * @param {string} code
    768      * @param {string} objectGroup
    769      * @param {boolean} includeCommandLineAPI
    770      * @param {boolean} doNotPauseOnExceptionsAndMuteConsole
    771      * @param {boolean} returnByValue
    772      * @param {boolean} generatePreview
    773      * @param {function(?RuntimeAgent.RemoteObject, boolean=)=} callback
    774      */
    775     evaluate: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
    776     {
    777         /**
    778          * @this {WebInspector.DebuggerModel.CallFrame}
    779          * @param {?Protocol.Error} error
    780          * @param {RuntimeAgent.RemoteObject} result
    781          * @param {boolean=} wasThrown
    782          */
    783         function didEvaluateOnCallFrame(error, result, wasThrown)
    784         {
    785             if (error) {
    786                 console.error(error);
    787                 callback(null, false);
    788                 return;
    789             }
    790             callback(result, wasThrown);
    791         }
    792         DebuggerAgent.evaluateOnCallFrame(this._payload.callFrameId, code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, didEvaluateOnCallFrame.bind(this));
    793     },
    794 
    795     /**
    796      * @param {function(?Protocol.Error=)=} callback
    797      */
    798     restart: function(callback)
    799     {
    800         /**
    801          * @this {WebInspector.DebuggerModel.CallFrame}
    802          * @param {?Protocol.Error} error
    803          * @param {Array.<DebuggerAgent.CallFrame>=} callFrames
    804          * @param {Object=} details
    805          */
    806         function protocolCallback(error, callFrames, details)
    807         {
    808             if (!error)
    809                 WebInspector.debuggerModel.callStackModified(callFrames, details);
    810             if (callback)
    811                 callback(error);
    812         }
    813         DebuggerAgent.restartFrame(this._payload.callFrameId, protocolCallback);
    814     },
    815 
    816     /**
    817      * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
    818      */
    819     createLiveLocation: function(updateDelegate)
    820     {
    821         var location = this._script.createLiveLocation(this.location, updateDelegate);
    822         this._locations.push(location);
    823         return location;
    824     },
    825 
    826     dispose: function(updateDelegate)
    827     {
    828         for (var i = 0; i < this._locations.length; ++i)
    829             this._locations[i].dispose();
    830         this._locations = [];
    831     }
    832 }
    833 
    834 /**
    835  * @constructor
    836  * @param {WebInspector.DebuggerModel} model
    837  * @param {Array.<DebuggerAgent.CallFrame>} callFrames
    838  * @param {string} reason
    839  * @param {Object|undefined} auxData
    840  * @param {Array.<string>} breakpointIds
    841  */
    842 WebInspector.DebuggerPausedDetails = function(model, callFrames, reason, auxData, breakpointIds)
    843 {
    844     this.callFrames = [];
    845     for (var i = 0; i < callFrames.length; ++i) {
    846         var callFrame = callFrames[i];
    847         var script = model.scriptForId(callFrame.location.scriptId);
    848         if (script)
    849             this.callFrames.push(new WebInspector.DebuggerModel.CallFrame(script, callFrame));
    850     }
    851     this.reason = reason;
    852     this.auxData = auxData;
    853     this.breakpointIds = breakpointIds;
    854 }
    855 
    856 WebInspector.DebuggerPausedDetails.prototype = {
    857     dispose: function()
    858     {
    859         for (var i = 0; i < this.callFrames.length; ++i) {
    860             var callFrame = this.callFrames[i];
    861             callFrame.dispose();
    862         }
    863     }
    864 }
    865 
    866 /**
    867  * @type {?WebInspector.DebuggerModel}
    868  */
    869 WebInspector.debuggerModel = null;
    870