Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C) 2009 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 var Capabilities = {
     32     isMainFrontend: false,
     33     canProfilePower: false,
     34 }
     35 
     36 /**
     37  * @constructor
     38  */
     39 WebInspector.Settings = function()
     40 {
     41     this._eventSupport = new WebInspector.Object();
     42     this._registry = /** @type {!Object.<string, !WebInspector.Setting>} */ ({});
     43 
     44     this.colorFormat = this.createSetting("colorFormat", "original");
     45     this.consoleHistory = this.createSetting("consoleHistory", []);
     46     this.domWordWrap = this.createSetting("domWordWrap", true);
     47     this.eventListenersFilter = this.createSetting("eventListenersFilter", "all");
     48     this.lastViewedScriptFile = this.createSetting("lastViewedScriptFile", "application");
     49     this.monitoringXHREnabled = this.createSetting("monitoringXHREnabled", false);
     50     this.preserveConsoleLog = this.createSetting("preserveConsoleLog", false);
     51     this.consoleTimestampsEnabled = this.createSetting("consoleTimestampsEnabled", false);
     52     this.resourcesLargeRows = this.createSetting("resourcesLargeRows", true);
     53     this.resourcesSortOptions = this.createSetting("resourcesSortOptions", {timeOption: "responseTime", sizeOption: "transferSize"});
     54     this.resourceViewTab = this.createSetting("resourceViewTab", "preview");
     55     this.showInheritedComputedStyleProperties = this.createSetting("showInheritedComputedStyleProperties", false);
     56     this.showUserAgentStyles = this.createSetting("showUserAgentStyles", true);
     57     this.watchExpressions = this.createSetting("watchExpressions", []);
     58     this.breakpoints = this.createSetting("breakpoints", []);
     59     this.eventListenerBreakpoints = this.createSetting("eventListenerBreakpoints", []);
     60     this.domBreakpoints = this.createSetting("domBreakpoints", []);
     61     this.xhrBreakpoints = this.createSetting("xhrBreakpoints", []);
     62     this.jsSourceMapsEnabled = this.createSetting("sourceMapsEnabled", true);
     63     this.cssSourceMapsEnabled = this.createSetting("cssSourceMapsEnabled", true);
     64     this.cacheDisabled = this.createSetting("cacheDisabled", false);
     65     this.showUAShadowDOM = this.createSetting("showUAShadowDOM", false);
     66     this.savedURLs = this.createSetting("savedURLs", {});
     67     this.javaScriptDisabled = this.createSetting("javaScriptDisabled", false);
     68     this.showAdvancedHeapSnapshotProperties = this.createSetting("showAdvancedHeapSnapshotProperties", false);
     69     this.highResolutionCpuProfiling = this.createSetting("highResolutionCpuProfiling", false);
     70     this.searchInContentScripts = this.createSetting("searchInContentScripts", false);
     71     this.textEditorIndent = this.createSetting("textEditorIndent", "    ");
     72     this.textEditorAutoDetectIndent = this.createSetting("textEditorAutoIndentIndent", true);
     73     this.textEditorAutocompletion = this.createSetting("textEditorAutocompletion", true);
     74     this.textEditorBracketMatching = this.createSetting("textEditorBracketMatching", true);
     75     this.cssReloadEnabled = this.createSetting("cssReloadEnabled", false);
     76     this.timelineLiveUpdate = this.createSetting("timelineLiveUpdate", true);
     77     this.showMetricsRulers = this.createSetting("showMetricsRulers", false);
     78     this.workerInspectorWidth = this.createSetting("workerInspectorWidth", 600);
     79     this.workerInspectorHeight = this.createSetting("workerInspectorHeight", 600);
     80     this.messageURLFilters = this.createSetting("messageURLFilters", {});
     81     this.networkHideDataURL = this.createSetting("networkHideDataURL", false);
     82     this.networkResourceTypeFilters = this.createSetting("networkResourceTypeFilters", {});
     83     this.messageLevelFilters = this.createSetting("messageLevelFilters", {});
     84     this.splitVerticallyWhenDockedToRight = this.createSetting("splitVerticallyWhenDockedToRight", true);
     85     this.visiblePanels = this.createSetting("visiblePanels", {});
     86     this.shortcutPanelSwitch = this.createSetting("shortcutPanelSwitch", false);
     87     this.showWhitespacesInEditor = this.createSetting("showWhitespacesInEditor", false);
     88     this.skipStackFramesSwitch = this.createSetting("skipStackFramesSwitch", false);
     89     this.skipStackFramesPattern = this.createRegExpSetting("skipStackFramesPattern", "");
     90     this.pauseOnExceptionEnabled = this.createSetting("pauseOnExceptionEnabled", false);
     91     this.pauseOnCaughtException = this.createSetting("pauseOnCaughtException", false);
     92     this.enableAsyncStackTraces = this.createSetting("enableAsyncStackTraces", false);
     93     this.showMediaQueryInspector = this.createSetting("showMediaQueryInspector", false);
     94 }
     95 
     96 WebInspector.Settings.prototype = {
     97     /**
     98      * @param {string} key
     99      * @param {*} defaultValue
    100      * @return {!WebInspector.Setting}
    101      */
    102     createSetting: function(key, defaultValue)
    103     {
    104         if (!this._registry[key])
    105             this._registry[key] = new WebInspector.Setting(key, defaultValue, this._eventSupport, window.localStorage);
    106         return this._registry[key];
    107     },
    108 
    109     /**
    110      * @param {string} key
    111      * @param {string} defaultValue
    112      * @param {string=} regexFlags
    113      * @return {!WebInspector.Setting}
    114      */
    115     createRegExpSetting: function(key, defaultValue, regexFlags)
    116     {
    117         if (!this._registry[key])
    118             this._registry[key] = new WebInspector.RegExpSetting(key, defaultValue, this._eventSupport, window.localStorage, regexFlags);
    119         return this._registry[key];
    120     },
    121 
    122     /**
    123      * @param {string} key
    124      * @param {*} defaultValue
    125      * @param {function(*, function(string, ...))} setterCallback
    126      * @return {!WebInspector.Setting}
    127      */
    128     createBackendSetting: function(key, defaultValue, setterCallback)
    129     {
    130         if (!this._registry[key])
    131             this._registry[key] = new WebInspector.BackendSetting(key, defaultValue, this._eventSupport, window.localStorage, setterCallback);
    132         return this._registry[key];
    133     },
    134 
    135     initializeBackendSettings: function()
    136     {
    137         this.showPaintRects = WebInspector.settings.createBackendSetting("showPaintRects", false, PageAgent.setShowPaintRects.bind(PageAgent));
    138         this.showDebugBorders = WebInspector.settings.createBackendSetting("showDebugBorders", false, PageAgent.setShowDebugBorders.bind(PageAgent));
    139         this.continuousPainting = WebInspector.settings.createBackendSetting("continuousPainting", false, PageAgent.setContinuousPaintingEnabled.bind(PageAgent));
    140         this.showFPSCounter = WebInspector.settings.createBackendSetting("showFPSCounter", false, PageAgent.setShowFPSCounter.bind(PageAgent));
    141         this.showScrollBottleneckRects = WebInspector.settings.createBackendSetting("showScrollBottleneckRects", false, PageAgent.setShowScrollBottleneckRects.bind(PageAgent));
    142     }
    143 }
    144 
    145 /**
    146  * @constructor
    147  * @param {string} name
    148  * @param {V} defaultValue
    149  * @param {!WebInspector.Object} eventSupport
    150  * @param {?Storage} storage
    151  * @template V
    152  */
    153 WebInspector.Setting = function(name, defaultValue, eventSupport, storage)
    154 {
    155     this._name = name;
    156     this._defaultValue = defaultValue;
    157     this._eventSupport = eventSupport;
    158     this._storage = storage;
    159 }
    160 
    161 WebInspector.Setting.prototype = {
    162     /**
    163      * @param {function(!WebInspector.Event)} listener
    164      * @param {!Object=} thisObject
    165      */
    166     addChangeListener: function(listener, thisObject)
    167     {
    168         this._eventSupport.addEventListener(this._name, listener, thisObject);
    169     },
    170 
    171     /**
    172      * @param {function(!WebInspector.Event)} listener
    173      * @param {!Object=} thisObject
    174      */
    175     removeChangeListener: function(listener, thisObject)
    176     {
    177         this._eventSupport.removeEventListener(this._name, listener, thisObject);
    178     },
    179 
    180     get name()
    181     {
    182         return this._name;
    183     },
    184 
    185     /**
    186      * @return {V}
    187      */
    188     get: function()
    189     {
    190         if (typeof this._value !== "undefined")
    191             return this._value;
    192 
    193         this._value = this._defaultValue;
    194         if (this._storage && this._name in this._storage) {
    195             try {
    196                 this._value = JSON.parse(this._storage[this._name]);
    197             } catch(e) {
    198                 delete this._storage[this._name];
    199             }
    200         }
    201         return this._value;
    202     },
    203 
    204     set: function(value)
    205     {
    206         this._value = value;
    207         if (this._storage) {
    208             try {
    209                 this._storage[this._name] = JSON.stringify(value);
    210             } catch(e) {
    211                 console.error("Error saving setting with name:" + this._name);
    212             }
    213         }
    214         this._eventSupport.dispatchEventToListeners(this._name, value);
    215     }
    216 }
    217 
    218 /**
    219  * @constructor
    220  * @extends {WebInspector.Setting}
    221  * @param {string} name
    222  * @param {string} defaultValue
    223  * @param {!WebInspector.Object} eventSupport
    224  * @param {?Storage} storage
    225  * @param {string=} regexFlags
    226  */
    227 WebInspector.RegExpSetting = function(name, defaultValue, eventSupport, storage, regexFlags)
    228 {
    229     WebInspector.Setting.call(this, name, defaultValue, eventSupport, storage);
    230     this._regexFlags = regexFlags;
    231 }
    232 
    233 WebInspector.RegExpSetting.prototype = {
    234     set: function(value)
    235     {
    236         delete this._regex;
    237         WebInspector.Setting.prototype.set.call(this, value);
    238     },
    239 
    240     /**
    241      * @return {?RegExp}
    242      */
    243     asRegExp: function()
    244     {
    245         if (typeof this._regex !== "undefined")
    246             return this._regex;
    247         this._regex = null;
    248         try {
    249             this._regex = new RegExp(this.get(), this._regexFlags || "");
    250         } catch (e) {
    251         }
    252         return this._regex;
    253     },
    254 
    255     __proto__: WebInspector.Setting.prototype
    256 }
    257 
    258 /**
    259  * @constructor
    260  * @extends {WebInspector.Setting}
    261  * @param {string} name
    262  * @param {*} defaultValue
    263  * @param {!WebInspector.Object} eventSupport
    264  * @param {?Storage} storage
    265  * @param {function(*,function(string, ...))} setterCallback
    266  */
    267 WebInspector.BackendSetting = function(name, defaultValue, eventSupport, storage, setterCallback)
    268 {
    269     WebInspector.Setting.call(this, name, defaultValue, eventSupport, storage);
    270     this._setterCallback = setterCallback;
    271     var currentValue = this.get();
    272     if (currentValue !== defaultValue)
    273         this.set(currentValue);
    274 }
    275 
    276 WebInspector.BackendSetting.prototype = {
    277     set: function(value)
    278     {
    279         /**
    280          * @param {?Protocol.Error} error
    281          * @this {WebInspector.BackendSetting}
    282          */
    283         function callback(error)
    284         {
    285             if (error) {
    286                 WebInspector.messageSink.addErrorMessage("Error applying setting " + this._name + ": " + error);
    287                 this._eventSupport.dispatchEventToListeners(this._name, this._value);
    288                 return;
    289             }
    290             WebInspector.Setting.prototype.set.call(this, value);
    291         }
    292         this._setterCallback(value, callback.bind(this));
    293     },
    294 
    295     __proto__: WebInspector.Setting.prototype
    296 }
    297 
    298 /**
    299  * @constructor
    300  * @param {boolean} experimentsEnabled
    301  */
    302 WebInspector.ExperimentsSettings = function(experimentsEnabled)
    303 {
    304     this._experimentsEnabled = experimentsEnabled;
    305     this._setting = WebInspector.settings.createSetting("experiments", {});
    306     this._experiments = [];
    307     this._enabledForTest = {};
    308 
    309     // Add currently running experiments here.
    310     this.applyCustomStylesheet = this._createExperiment("applyCustomStylesheet", "Allow custom UI themes");
    311     this.canvasInspection = this._createExperiment("canvasInspection ", "Canvas inspection");
    312     this.devicesPanel = this._createExperiment("devicesPanel", "Devices panel", true);
    313     this.disableAgentsWhenProfile = this._createExperiment("disableAgentsWhenProfile", "Disable other agents and UI when profiler is active", true);
    314     this.dockToLeft = this._createExperiment("dockToLeft", "Dock to left", true);
    315     this.editorInDrawer = this._createExperiment("showEditorInDrawer", "Editor in drawer", true);
    316     this.fileSystemInspection = this._createExperiment("fileSystemInspection", "FileSystem inspection");
    317     this.frameworksDebuggingSupport = this._createExperiment("frameworksDebuggingSupport", "JavaScript frameworks debugging");
    318     this.gpuTimeline = this._createExperiment("gpuTimeline", "GPU data on timeline", true);
    319     this.heapAllocationProfiler = this._createExperiment("allocationProfiler", "Heap allocation profiler");
    320     this.heapSnapshotStatistics = this._createExperiment("heapSnapshotStatistics", "Heap snapshot statistics", true);
    321     this.layersPanel = this._createExperiment("layersPanel", "Layers panel", true);
    322     this.networkConditions = this._createExperiment("networkConditions", "Network conditions", true);
    323     this.responsiveDesign = this._createExperiment("responsiveDesign", "Responsive design");
    324     this.timelineFlameChart = this._createExperiment("timelineFlameChart", "Timeline flame chart");
    325     this.timelineOnTraceEvents = this._createExperiment("timelineOnTraceEvents", "Timeline on trace events", true);
    326     this.timelinePowerProfiler = this._createExperiment("timelinePowerProfiler", "Timeline power profiler");
    327     this.timelineTracingMode = this._createExperiment("timelineTracingMode", "Timeline tracing mode");
    328     this.timelineJSCPUProfile = this._createExperiment("timelineJSCPUProfile", "Timeline with JS sampling");
    329     this.timelineNoLiveUpdate = this._createExperiment("timelineNoLiveUpdate", "Timeline w/o live update", true);
    330     this.workersInMainWindow = this._createExperiment("workersInMainWindow", "Workers in main window", true);
    331 
    332     this._cleanUpSetting();
    333 }
    334 
    335 WebInspector.ExperimentsSettings.prototype = {
    336     /**
    337      * @return {!Array.<!WebInspector.Experiment>}
    338      */
    339     get experiments()
    340     {
    341         return this._experiments.slice();
    342     },
    343 
    344     /**
    345      * @return {boolean}
    346      */
    347     get experimentsEnabled()
    348     {
    349         return this._experimentsEnabled;
    350     },
    351 
    352     /**
    353      * @param {string} experimentName
    354      * @param {string} experimentTitle
    355      * @param {boolean=} hidden
    356      * @return {!WebInspector.Experiment}
    357      */
    358     _createExperiment: function(experimentName, experimentTitle, hidden)
    359     {
    360         var experiment = new WebInspector.Experiment(this, experimentName, experimentTitle, !!hidden);
    361         this._experiments.push(experiment);
    362         return experiment;
    363     },
    364 
    365     /**
    366      * @param {string} experimentName
    367      * @return {boolean}
    368      */
    369     isEnabled: function(experimentName)
    370     {
    371         if (this._enabledForTest[experimentName])
    372             return true;
    373 
    374         if (!this.experimentsEnabled)
    375             return false;
    376 
    377         var experimentsSetting = this._setting.get();
    378         return experimentsSetting[experimentName];
    379     },
    380 
    381     /**
    382      * @param {string} experimentName
    383      * @param {boolean} enabled
    384      */
    385     setEnabled: function(experimentName, enabled)
    386     {
    387         var experimentsSetting = this._setting.get();
    388         experimentsSetting[experimentName] = enabled;
    389         this._setting.set(experimentsSetting);
    390     },
    391 
    392     /**
    393      * @param {string} experimentName
    394      */
    395     _enableForTest: function(experimentName)
    396     {
    397         this._enabledForTest[experimentName] = true;
    398     },
    399 
    400     _cleanUpSetting: function()
    401     {
    402         var experimentsSetting = this._setting.get();
    403         var cleanedUpExperimentSetting = {};
    404         for (var i = 0; i < this._experiments.length; ++i) {
    405             var experimentName = this._experiments[i].name;
    406             if (experimentsSetting[experimentName])
    407                 cleanedUpExperimentSetting[experimentName] = true;
    408         }
    409         this._setting.set(cleanedUpExperimentSetting);
    410     }
    411 }
    412 
    413 /**
    414  * @constructor
    415  * @param {!WebInspector.ExperimentsSettings} experimentsSettings
    416  * @param {string} name
    417  * @param {string} title
    418  * @param {boolean} hidden
    419  */
    420 WebInspector.Experiment = function(experimentsSettings, name, title, hidden)
    421 {
    422     this._name = name;
    423     this._title = title;
    424     this._hidden = hidden;
    425     this._experimentsSettings = experimentsSettings;
    426 }
    427 
    428 WebInspector.Experiment.prototype = {
    429     /**
    430      * @return {string}
    431      */
    432     get name()
    433     {
    434         return this._name;
    435     },
    436 
    437     /**
    438      * @return {string}
    439      */
    440     get title()
    441     {
    442         return this._title;
    443     },
    444 
    445     /**
    446      * @return {boolean}
    447      */
    448     get hidden()
    449     {
    450         return this._hidden;
    451     },
    452 
    453     /**
    454      * @return {boolean}
    455      */
    456     isEnabled: function()
    457     {
    458         return this._experimentsSettings.isEnabled(this._name);
    459     },
    460 
    461     /**
    462      * @param {boolean} enabled
    463      */
    464     setEnabled: function(enabled)
    465     {
    466         this._experimentsSettings.setEnabled(this._name, enabled);
    467     },
    468 
    469     enableForTest: function()
    470     {
    471         this._experimentsSettings._enableForTest(this._name);
    472     }
    473 }
    474 
    475 /**
    476  * @constructor
    477  */
    478 WebInspector.VersionController = function()
    479 {
    480 }
    481 
    482 WebInspector.VersionController.currentVersion = 8;
    483 
    484 WebInspector.VersionController.prototype = {
    485     updateVersion: function()
    486     {
    487         var versionSetting = WebInspector.settings.createSetting("inspectorVersion", 0);
    488         var currentVersion = WebInspector.VersionController.currentVersion;
    489         var oldVersion = versionSetting.get();
    490         var methodsToRun = this._methodsToRunToUpdateVersion(oldVersion, currentVersion);
    491         for (var i = 0; i < methodsToRun.length; ++i)
    492             this[methodsToRun[i]].call(this);
    493         versionSetting.set(currentVersion);
    494     },
    495 
    496     /**
    497      * @param {number} oldVersion
    498      * @param {number} currentVersion
    499      */
    500     _methodsToRunToUpdateVersion: function(oldVersion, currentVersion)
    501     {
    502         var result = [];
    503         for (var i = oldVersion; i < currentVersion; ++i)
    504             result.push("_updateVersionFrom" + i + "To" + (i + 1));
    505         return result;
    506     },
    507 
    508     _updateVersionFrom0To1: function()
    509     {
    510         this._clearBreakpointsWhenTooMany(WebInspector.settings.breakpoints, 500000);
    511     },
    512 
    513     _updateVersionFrom1To2: function()
    514     {
    515         var versionSetting = WebInspector.settings.createSetting("previouslyViewedFiles", []);
    516         versionSetting.set([]);
    517     },
    518 
    519     _updateVersionFrom2To3: function()
    520     {
    521         var fileSystemMappingSetting = WebInspector.settings.createSetting("fileSystemMapping", {});
    522         fileSystemMappingSetting.set({});
    523         if (window.localStorage)
    524             delete window.localStorage["fileMappingEntries"];
    525     },
    526 
    527     _updateVersionFrom3To4: function()
    528     {
    529         var advancedMode = WebInspector.settings.createSetting("showHeaSnapshotObjectsHiddenProperties", false).get();
    530         WebInspector.settings.showAdvancedHeapSnapshotProperties.set(advancedMode);
    531     },
    532 
    533     _updateVersionFrom4To5: function()
    534     {
    535         if (!window.localStorage)
    536             return;
    537         var settingNames = {
    538             "FileSystemViewSidebarWidth": "fileSystemViewSplitViewState",
    539             "canvasProfileViewReplaySplitLocation": "canvasProfileViewReplaySplitViewState",
    540             "canvasProfileViewSplitLocation": "canvasProfileViewSplitViewState",
    541             "elementsSidebarWidth": "elementsPanelSplitViewState",
    542             "StylesPaneSplitRatio": "stylesPaneSplitViewState",
    543             "heapSnapshotRetainersViewSize": "heapSnapshotSplitViewState",
    544             "InspectorView.splitView": "InspectorView.splitViewState",
    545             "InspectorView.screencastSplitView": "InspectorView.screencastSplitViewState",
    546             "Inspector.drawerSplitView": "Inspector.drawerSplitViewState",
    547             "layerDetailsSplitView": "layerDetailsSplitViewState",
    548             "networkSidebarWidth": "networkPanelSplitViewState",
    549             "sourcesSidebarWidth": "sourcesPanelSplitViewState",
    550             "scriptsPanelNavigatorSidebarWidth": "sourcesPanelNavigatorSplitViewState",
    551             "sourcesPanelSplitSidebarRatio": "sourcesPanelDebuggerSidebarSplitViewState",
    552             "timeline-details": "timelinePanelDetailsSplitViewState",
    553             "timeline-split": "timelinePanelRecorsSplitViewState",
    554             "timeline-view": "timelinePanelTimelineStackSplitViewState",
    555             "auditsSidebarWidth": "auditsPanelSplitViewState",
    556             "layersSidebarWidth": "layersPanelSplitViewState",
    557             "profilesSidebarWidth": "profilesPanelSplitViewState",
    558             "resourcesSidebarWidth": "resourcesPanelSplitViewState"
    559         };
    560         for (var oldName in settingNames) {
    561             var newName = settingNames[oldName];
    562             var oldNameH = oldName + "H";
    563 
    564             var newValue = null;
    565             var oldSetting = WebInspector.settings.createSetting(oldName, undefined).get();
    566             if (oldSetting) {
    567                 newValue = newValue || {};
    568                 newValue.vertical = {};
    569                 newValue.vertical.size = oldSetting;
    570                 delete window.localStorage[oldName];
    571             }
    572             var oldSettingH = WebInspector.settings.createSetting(oldNameH, undefined).get();
    573             if (oldSettingH) {
    574                 newValue = newValue || {};
    575                 newValue.horizontal = {};
    576                 newValue.horizontal.size = oldSettingH;
    577                 delete window.localStorage[oldNameH];
    578             }
    579             var newSetting = WebInspector.settings.createSetting(newName, {});
    580             if (newValue)
    581                 newSetting.set(newValue);
    582         }
    583     },
    584 
    585     _updateVersionFrom5To6: function()
    586     {
    587         if (!window.localStorage)
    588             return;
    589 
    590         var settingNames = {
    591             "debuggerSidebarHidden": "sourcesPanelSplitViewState",
    592             "navigatorHidden": "sourcesPanelNavigatorSplitViewState",
    593             "WebInspector.Drawer.showOnLoad": "Inspector.drawerSplitViewState"
    594         };
    595 
    596         for (var oldName in settingNames) {
    597             var newName = settingNames[oldName];
    598 
    599             var oldSetting = WebInspector.settings.createSetting(oldName, undefined).get();
    600             var invert = "WebInspector.Drawer.showOnLoad" === oldName;
    601             var hidden = !!oldSetting !== invert;
    602             delete window.localStorage[oldName];
    603             var showMode = hidden ? "OnlyMain" : "Both";
    604 
    605             var newSetting = WebInspector.settings.createSetting(newName, null);
    606             var newValue = newSetting.get() || {};
    607             newValue.vertical = newValue.vertical || {};
    608             newValue.vertical.showMode = showMode;
    609             newValue.horizontal = newValue.horizontal || {};
    610             newValue.horizontal.showMode = showMode;
    611             newSetting.set(newValue);
    612         }
    613     },
    614 
    615     _updateVersionFrom6To7: function()
    616     {
    617         if (!window.localStorage)
    618             return;
    619 
    620         var settingNames = {
    621             "sourcesPanelNavigatorSplitViewState": "sourcesPanelNavigatorSplitViewState",
    622             "elementsPanelSplitViewState": "elementsPanelSplitViewState",
    623             "canvasProfileViewReplaySplitViewState": "canvasProfileViewReplaySplitViewState",
    624             "editorInDrawerSplitViewState": "editorInDrawerSplitViewState",
    625             "stylesPaneSplitViewState": "stylesPaneSplitViewState",
    626             "sourcesPanelDebuggerSidebarSplitViewState": "sourcesPanelDebuggerSidebarSplitViewState"
    627         };
    628 
    629         for (var name in settingNames) {
    630             if (!(name in window.localStorage))
    631                 continue;
    632             var setting = WebInspector.settings.createSetting(name, undefined);
    633             var value = setting.get();
    634             if (!value)
    635                 continue;
    636             // Zero out saved percentage sizes, and they will be restored to defaults.
    637             if (value.vertical && value.vertical.size && value.vertical.size < 1)
    638                 value.vertical.size = 0;
    639             if (value.horizontal && value.horizontal.size && value.horizontal.size < 1)
    640                 value.horizontal.size = 0;
    641             setting.set(value);
    642         }
    643     },
    644 
    645     _updateVersionFrom7To8: function()
    646     {
    647         var settingName = "deviceMetrics";
    648         if (!window.localStorage || !(settingName in window.localStorage))
    649             return;
    650         var setting = WebInspector.settings.createSetting(settingName, undefined);
    651         var value = setting.get();
    652         if (!value)
    653             return;
    654 
    655         var components = value.split("x");
    656         if (components.length >= 3) {
    657             var width = parseInt(components[0], 10);
    658             var height = parseInt(components[1], 10);
    659             var deviceScaleFactor = parseFloat(components[2]);
    660             if (deviceScaleFactor) {
    661                 components[0] = "" + Math.round(width / deviceScaleFactor);
    662                 components[1] = "" + Math.round(height / deviceScaleFactor);
    663             }
    664         }
    665         value = components.join("x");
    666         setting.set(value);
    667     },
    668 
    669     /**
    670      * @param {!WebInspector.Setting} breakpointsSetting
    671      * @param {number} maxBreakpointsCount
    672      */
    673     _clearBreakpointsWhenTooMany: function(breakpointsSetting, maxBreakpointsCount)
    674     {
    675         // If there are too many breakpoints in a storage, it is likely due to a recent bug that caused
    676         // periodical breakpoints duplication leading to inspector slowness.
    677         if (breakpointsSetting.get().length > maxBreakpointsCount)
    678             breakpointsSetting.set([]);
    679     }
    680 }
    681 
    682 /**
    683  * @type {!WebInspector.Settings}
    684  */
    685 WebInspector.settings;
    686 
    687 /**
    688  * @type {!WebInspector.ExperimentsSettings}
    689  */
    690 WebInspector.experimentsSettings;
    691 
    692 // These methods are added for backwards compatibility with Devtools CodeSchool extension.
    693 // DO NOT REMOVE
    694 
    695 /**
    696  * @constructor
    697  */
    698 WebInspector.PauseOnExceptionStateSetting = function()
    699 {
    700     WebInspector.settings.pauseOnExceptionEnabled.addChangeListener(this._enabledChanged, this);
    701     WebInspector.settings.pauseOnCaughtException.addChangeListener(this._pauseOnCaughtChanged, this);
    702     this._name = "pauseOnExceptionStateString";
    703     this._eventSupport = new WebInspector.Object();
    704     this._value = this._calculateValue();
    705 }
    706 
    707 WebInspector.PauseOnExceptionStateSetting.prototype = {
    708     /**
    709      * @param {function(!WebInspector.Event)} listener
    710      * @param {!Object=} thisObject
    711      */
    712     addChangeListener: function(listener, thisObject)
    713     {
    714         this._eventSupport.addEventListener(this._name, listener, thisObject);
    715     },
    716 
    717     /**
    718      * @param {function(!WebInspector.Event)} listener
    719      * @param {!Object=} thisObject
    720      */
    721     removeChangeListener: function(listener, thisObject)
    722     {
    723         this._eventSupport.removeEventListener(this._name, listener, thisObject);
    724     },
    725 
    726     /**
    727      * @return {string}
    728      */
    729     get: function()
    730     {
    731         return this._value;
    732     },
    733 
    734     /**
    735      * @return {string}
    736      */
    737     _calculateValue: function()
    738     {
    739         if (!WebInspector.settings.pauseOnExceptionEnabled.get())
    740             return "none";
    741         // The correct code here would be
    742         //     return WebInspector.settings.pauseOnCaughtException.get() ? "all" : "uncaught";
    743         // But the CodeSchool DevTools relies on the fact that we used to enable pausing on ALL extensions by default, so we trick it here.
    744         return "all";
    745     },
    746 
    747     _enabledChanged: function(event)
    748     {
    749         this._fireChangedIfNeeded();
    750     },
    751 
    752     _pauseOnCaughtChanged: function(event)
    753     {
    754         this._fireChangedIfNeeded();
    755     },
    756 
    757     _fireChangedIfNeeded: function()
    758     {
    759         var newValue = this._calculateValue();
    760         if (newValue === this._value)
    761             return;
    762         this._value = newValue;
    763         this._eventSupport.dispatchEventToListeners(this._name, this._value);
    764     }
    765 }
    766