diff options
Diffstat (limited to 'Source/WebCore/inspector/front-end')
62 files changed, 4361 insertions, 2529 deletions
diff --git a/Source/WebCore/inspector/front-end/ApplicationCacheItemsView.js b/Source/WebCore/inspector/front-end/ApplicationCacheItemsView.js index e7aa188..b345749 100644 --- a/Source/WebCore/inspector/front-end/ApplicationCacheItemsView.js +++ b/Source/WebCore/inspector/front-end/ApplicationCacheItemsView.js @@ -136,7 +136,7 @@ WebInspector.ApplicationCacheItemsView.prototype = { _update: function() { - WebInspector.ApplicationCache.getApplicationCachesAsync(this._updateCallback.bind(this)); + WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync(this._updateCallback.bind(this)); }, _updateCallback: function(applicationCaches) diff --git a/Source/WebCore/inspector/front-end/AuditRules.js b/Source/WebCore/inspector/front-end/AuditRules.js index c2bbcbb..c122ba4 100644 --- a/Source/WebCore/inspector/front-end/AuditRules.js +++ b/Source/WebCore/inspector/front-end/AuditRules.js @@ -326,7 +326,7 @@ WebInspector.AuditRules.UnusedCssRule.prototype = { if (!unusedRules.length) continue; - var resource = WebInspector.resourceTreeModel.resourceForURL(styleSheet.sourceURL); + var resource = WebInspector.resourceForURL(styleSheet.sourceURL); var isInlineBlock = resource && resource.type == WebInspector.Resource.Type.Document; var url = !isInlineBlock ? WebInspector.AuditRuleResult.linkifyDisplayName(styleSheet.sourceURL) : String.sprintf("Inline block #%d", ++inlineBlockOrdinal); var pctUnused = Math.round(100 * unusedStylesheetSize / stylesheetSize); @@ -383,7 +383,7 @@ WebInspector.AuditRules.UnusedCssRule.prototype = { WebInspector.CSSStyleSheet.createForId(styleSheetIds[i], styleSheetCallback.bind(null, styleSheets, i == styleSheetIds.length - 1 ? evalCallback : null)); } - InspectorBackend.getAllStyles2(allStylesCallback); + InspectorBackend.getAllStyles(allStylesCallback); } } diff --git a/Source/WebCore/inspector/front-end/AuditsPanel.js b/Source/WebCore/inspector/front-end/AuditsPanel.js index f3cbfa7..47c0b30 100644 --- a/Source/WebCore/inspector/front-end/AuditsPanel.js +++ b/Source/WebCore/inspector/front-end/AuditsPanel.js @@ -192,7 +192,7 @@ WebInspector.AuditsPanel.prototype = { _reloadResources: function(callback) { this._pageReloadCallback = callback; - InspectorBackend.reloadPage(); + InspectorBackend.reloadPage(false); }, _didMainResourceLoad: function() diff --git a/Source/WebCore/inspector/front-end/Breakpoint.js b/Source/WebCore/inspector/front-end/Breakpoint.js index aa600a7..ebc6029 100644 --- a/Source/WebCore/inspector/front-end/Breakpoint.js +++ b/Source/WebCore/inspector/front-end/Breakpoint.js @@ -29,47 +29,21 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.Breakpoint = function(debuggerModel, breakpointId, sourceID, url, line, enabled, condition) +WebInspector.Breakpoint = function(id, url, sourceID, lineNumber, columnNumber, condition, enabled) { - this.id = breakpointId; + this.id = id; this.url = url; - this.line = line; this.sourceID = sourceID; - this._enabled = enabled; - this._condition = condition || ""; - this._debuggerModel = debuggerModel; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.condition = condition; + this.enabled = enabled; + this.locations = []; } WebInspector.Breakpoint.prototype = { - get enabled() + addLocation: function(sourceID, lineNumber, columnNumber) { - return this._enabled; - }, - - set enabled(enabled) - { - if (this._enabled === enabled) - return; - this.remove(); - WebInspector.debuggerModel.setBreakpoint(this.sourceID, this.line, enabled, this.condition); - }, - - get condition() - { - return this._condition; - }, - - get data() - { - return { id: this.id, url: this.url, sourceID: this.sourceID, lineNumber: this.line, condition: this.condition }; - }, - - remove: function() - { - this._debuggerModel.removeBreakpoint(this.id); - this.removeAllListeners(); - delete this._debuggerModel; + this.locations.push({ sourceID: sourceID, lineNumber: lineNumber, columnNumber: columnNumber }); } } - -WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/Source/WebCore/inspector/front-end/BreakpointManager.js b/Source/WebCore/inspector/front-end/BreakpointManager.js index d943d5b..94345d5 100644 --- a/Source/WebCore/inspector/front-end/BreakpointManager.js +++ b/Source/WebCore/inspector/front-end/BreakpointManager.js @@ -34,22 +34,17 @@ WebInspector.BreakpointManager = function() var breakpoints = WebInspector.settings.findSettingForAllProjects("nativeBreakpoints"); for (var projectId in breakpoints) this._stickyBreakpoints[projectId] = this._validateBreakpoints(breakpoints[projectId]); - InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints); this._breakpoints = {}; this._domBreakpointsRestored = false; - this._scriptBreakpoints = {}; WebInspector.settings.addEventListener(WebInspector.Settings.Events.ProjectChanged, this._projectChanged, this); - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._scriptBreakpointAdded, this); - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._scriptBreakpointRemoved, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); } WebInspector.BreakpointManager.BreakpointTypes = { DOM: "DOM", - JS: "JS", EventListener: "EventListener", XHR: "XHR" } @@ -104,38 +99,6 @@ WebInspector.BreakpointManager.prototype = { this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.EventListenerBreakpointAdded, breakpoint.view); }, - _createJavaScriptBreakpoint: function(url, lineNumber, condition, enabled, restored) - { - var breakpointId = this._createJavaScriptBreakpointId(url, lineNumber); - if (breakpointId in this._breakpoints) - return; - - var breakpoint = new WebInspector.JavaScriptBreakpoint(url, lineNumber, condition); - this._setBreakpoint(breakpointId, breakpoint, enabled, restored); - }, - - _scriptBreakpointAdded: function(event) - { - var scriptBreakpoint = event.data; - - if (!scriptBreakpoint.url) - return; - - if (!scriptBreakpoint.restored) - this._createJavaScriptBreakpoint(scriptBreakpoint.url, scriptBreakpoint.originalLineNumber, scriptBreakpoint.condition, scriptBreakpoint.enabled, false); - var breakpointId = this._createJavaScriptBreakpointId(scriptBreakpoint.url, scriptBreakpoint.originalLineNumber); - this._scriptBreakpoints[scriptBreakpoint.id] = breakpointId; - }, - - _scriptBreakpointRemoved: function(event) - { - var scriptBreakpointId = event.data; - var breakpointId = this._scriptBreakpoints[scriptBreakpointId]; - delete this._scriptBreakpoints[scriptBreakpointId]; - if (breakpointId in this._breakpoints) - this._removeBreakpoint(breakpointId); - }, - createXHRBreakpoint: function(url) { this._createXHRBreakpoint(url, true, false); @@ -232,7 +195,6 @@ WebInspector.BreakpointManager.prototype = { { this._breakpoints = {}; this._domBreakpointsRestored = false; - this._scriptBreakpoints = {}; this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.ProjectChanged); var breakpoints = this._stickyBreakpoints[WebInspector.settings.projectId] || []; @@ -240,11 +202,14 @@ WebInspector.BreakpointManager.prototype = { var breakpoint = breakpoints[i]; if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.EventListener) this._createEventListenerBreakpoint(breakpoint.condition.eventName, breakpoint.enabled, true); - else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.JS) - this._createJavaScriptBreakpoint(breakpoint.condition.url, breakpoint.condition.lineNumber, breakpoint.condition.condition, breakpoint.enabled, true); else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.XHR) this._createXHRBreakpoint(breakpoint.condition.url, breakpoint.enabled, true); } + + if (!this._breakpointsPushedToFrontend) { + InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints); + this._breakpointsPushedToFrontend = true; + } }, restoreDOMBreakpoints: function() @@ -324,15 +289,12 @@ WebInspector.BreakpointManager.prototype = { if (typeof condition.eventName !== "string") continue; id += condition.eventName; - } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.JS) { - if (typeof condition.url !== "string" || typeof condition.lineNumber !== "number" || typeof condition.condition !== "string") - continue; - id += condition.url + ":" + condition.lineNumber; } else if (breakpoint.type === WebInspector.BreakpointManager.BreakpointTypes.XHR) { if (typeof condition.url !== "string") continue; id += condition.url; - } + } else + continue; if (id in breakpointsSet) continue; breakpointsSet[id] = true; @@ -346,11 +308,6 @@ WebInspector.BreakpointManager.prototype = { return "dom:" + nodeId + ":" + type; }, - _createJavaScriptBreakpointId: function(url, lineNumber) - { - return "js:" + url + ":" + lineNumber; - }, - _createEventListenerBreakpointId: function(eventName) { return "eventListner:" + eventName; @@ -389,29 +346,6 @@ WebInspector.DOMBreakpoint.prototype = { } } -WebInspector.JavaScriptBreakpoint = function(url, lineNumber, condition) -{ - this._url = url; - this._lineNumber = lineNumber; - this._condition = condition; -} - -WebInspector.JavaScriptBreakpoint.prototype = { - _enable: function() - { - }, - - _disable: function() - { - }, - - _serializeToJSON: function() - { - var type = WebInspector.BreakpointManager.BreakpointTypes.JS; - return { type: type, condition: { url: this._url, lineNumber: this._lineNumber, condition: this._condition } }; - } -} - WebInspector.EventListenerBreakpoint = function(eventName) { this._eventName = eventName; diff --git a/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js index b237ca2..0a47bf8 100644 --- a/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -40,6 +40,8 @@ WebInspector.JavaScriptBreakpointsSidebarPane = function(title) WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); WebInspector.breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.ProjectChanged, this._projectChanged, this); @@ -50,7 +52,9 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { { var breakpoint = event.data; var breakpointId = breakpoint.id; - var data = breakpoint.data; + + if (breakpoint.url && !WebInspector.debuggerModel.scriptsForURL(breakpoint.url).length) + return; var element = document.createElement("li"); @@ -64,7 +68,7 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { var label = document.createElement("span"); element.appendChild(label); - element._data = data; + element._data = breakpoint; var currentElement = this.listElement.firstChild; while (currentElement) { if (currentElement._data && this._compareBreakpoints(currentElement._data, element._data) > 0) @@ -75,10 +79,9 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this, breakpointId), true); - this._setupBreakpointElement(data, element); + this._setupBreakpointElement(breakpoint, element); var breakpointItem = {}; - breakpointItem.data = data; breakpointItem.element = element; breakpointItem.checkbox = checkbox; this._items[breakpointId] = breakpointItem; @@ -97,6 +100,23 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { } }, + _breakpointResolved: function(event) + { + var breakpoint = event.data; + this._breakpointRemoved({ data: breakpoint.id }); + this._breakpointAdded({ data: breakpoint }); + }, + + _parsedScriptSource: function(event) + { + var url = event.data.sourceURL; + var breakpoints = WebInspector.debuggerModel.breakpoints; + for (var id in breakpoints) { + if (!(id in this._items)) + this._breakpointAdded({ data: breakpoints[id] }); + } + }, + _breakpointEnableChanged: function(enabled, event) { var breakpointId = event.data; @@ -107,7 +127,8 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { _breakpointItemCheckboxClicked: function(breakpointId, event) { - this._setBreakpointEnabled(breakpointId, event.target.checked); + var breakpoint = WebInspector.debuggerModel.breakpointForId(breakpointId); + WebInspector.debuggerModel.updateBreakpoint(breakpointId, breakpoint.condition, event.target.checked); // Breakpoint element may have it's own click handler. event.stopPropagation(); @@ -186,23 +207,32 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { _setupBreakpointElement: function(data, element) { + var sourceID; + var lineNumber = data.lineNumber; + if (data.locations.length) { + sourceID = data.locations[0].sourceID; + lineNumber = data.locations[0].lineNumber; + } + var displayName = data.url ? WebInspector.displayNameForURL(data.url) : WebInspector.UIString("(program)"); - var labelElement = document.createTextNode(displayName + ":" + data.lineNumber); + var labelElement = document.createTextNode(displayName + ":" + (lineNumber + 1)); element.appendChild(labelElement); var sourceTextElement = document.createElement("div"); sourceTextElement.className = "source-text monospace"; element.appendChild(sourceTextElement); - function didGetSourceLine(text) - { - sourceTextElement.textContent = text; + if (sourceID) { + function didGetSourceLine(text) + { + sourceTextElement.textContent = text; + } + var script = WebInspector.debuggerModel.scriptForSourceID(sourceID); + script.sourceLine(lineNumber, didGetSourceLine.bind(this)); } - var script = WebInspector.debuggerModel.scriptForSourceID(data.sourceID); - script.sourceLine(data.lineNumber, didGetSourceLine.bind(this)); element.addStyleClass("cursor-pointer"); - var clickHandler = WebInspector.panels.scripts.showSourceLine.bind(WebInspector.panels.scripts, data.url, data.lineNumber); + var clickHandler = WebInspector.panels.scripts.showSourceLine.bind(WebInspector.panels.scripts, data.url, lineNumber + 1); element.addEventListener("click", clickHandler, false); }, @@ -214,13 +244,6 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { return breakpoint.id; }, - _setBreakpointEnabled: function(breakpointId, enabled) - { - var breakpoint = WebInspector.debuggerModel.breakpointForId(breakpointId); - WebInspector.debuggerModel.removeBreakpoint(breakpointId); - WebInspector.debuggerModel.setBreakpoint(breakpoint.sourceID, breakpoint.line, enabled, breakpoint.condition); - }, - _removeBreakpoint: function(breakpointId) { WebInspector.debuggerModel.removeBreakpoint(breakpointId); diff --git a/Source/WebCore/inspector/front-end/CSSCompletions.js b/Source/WebCore/inspector/front-end/CSSCompletions.js index f60c297..ba3aca2 100644 --- a/Source/WebCore/inspector/front-end/CSSCompletions.js +++ b/Source/WebCore/inspector/front-end/CSSCompletions.js @@ -30,10 +30,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.CSSCompletions = function(values) +WebInspector.CSSCompletions = function(values, acceptEmptyPrefix) { this._values = values.slice(); this._values.sort(); + this._acceptEmptyPrefix = acceptEmptyPrefix; } WebInspector.CSSCompletions.prototype = { @@ -57,10 +58,10 @@ WebInspector.CSSCompletions.prototype = { _firstIndexOfPrefix: function(prefix) { - if (!prefix) - return -1; if (!this._values.length) return -1; + if (!prefix) + return this._acceptEmptyPrefix ? 0 : -1; var maxIndex = this._values.length - 1; var minIndex = 0; diff --git a/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js b/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js index ac62aff..de2072a 100755 --- a/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js +++ b/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js @@ -38,7 +38,7 @@ WebInspector.CSSKeywordCompletions = { acceptedKeywords = acceptedKeywords.concat(WebInspector.CSSKeywordCompletions._colors); if (propertyName in WebInspector.StylesSidebarPane.InheritedProperties) acceptedKeywords.push("inherit"); - return new WebInspector.CSSCompletions(acceptedKeywords); + return new WebInspector.CSSCompletions(acceptedKeywords, true); } }; diff --git a/Source/WebCore/inspector/front-end/CSSStyleModel.js b/Source/WebCore/inspector/front-end/CSSStyleModel.js index 4f20660..69bd7a9 100644 --- a/Source/WebCore/inspector/front-end/CSSStyleModel.js +++ b/Source/WebCore/inspector/front-end/CSSStyleModel.js @@ -83,7 +83,7 @@ WebInspector.CSSStyleModel.prototype = { userCallback(result); } - InspectorBackend.getStylesForNode2(nodeId, callback.bind(null, userCallback)); + InspectorBackend.getStylesForNode(nodeId, callback.bind(null, userCallback)); }, getComputedStyleAsync: function(nodeId, userCallback) @@ -96,7 +96,7 @@ WebInspector.CSSStyleModel.prototype = { userCallback(WebInspector.CSSStyleDeclaration.parsePayload(stylePayload)); } - InspectorBackend.getComputedStyleForNode2(nodeId, callback.bind(null, userCallback)); + InspectorBackend.getComputedStyleForNode(nodeId, callback.bind(null, userCallback)); }, getInlineStyleAsync: function(nodeId, userCallback) @@ -109,7 +109,7 @@ WebInspector.CSSStyleModel.prototype = { userCallback(WebInspector.CSSStyleDeclaration.parsePayload(stylePayload)); } - InspectorBackend.getInlineStyleForNode2(nodeId, callback.bind(null, userCallback)); + InspectorBackend.getInlineStyleForNode(nodeId, callback.bind(null, userCallback)); }, setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback) @@ -130,7 +130,7 @@ WebInspector.CSSStyleModel.prototype = { InspectorBackend.querySelectorAll(nodeId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); } - InspectorBackend.setRuleSelector2(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback)); + InspectorBackend.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback)); }, addRule: function(nodeId, selector, successCallback, failureCallback) @@ -152,7 +152,7 @@ WebInspector.CSSStyleModel.prototype = { InspectorBackend.querySelectorAll(nodeId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); } - InspectorBackend.addRule2(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector)); + InspectorBackend.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector)); }, _styleSheetChanged: function(styleSheetId, majorChange) @@ -162,11 +162,11 @@ WebInspector.CSSStyleModel.prototype = { function callback(href, content) { - var resource = WebInspector.resourceTreeModel.resourceForURL(href); + var resource = WebInspector.resourceForURL(href); if (resource && resource.type === WebInspector.Resource.Type.Stylesheet) resource.setContent(content, this._onRevert.bind(this, styleSheetId)); } - InspectorBackend.getStyleSheetText2(styleSheetId, callback.bind(this)); + InspectorBackend.getStyleSheetText(styleSheetId, callback.bind(this)); }, _onRevert: function(styleSheetId, contentToRevertTo) @@ -176,7 +176,7 @@ WebInspector.CSSStyleModel.prototype = { this._styleSheetChanged(styleSheetId, true); this.dispatchEventToListeners("stylesheet changed"); } - InspectorBackend.setStyleSheetText2(styleSheetId, contentToRevertTo, callback.bind(this)); + InspectorBackend.setStyleSheetText(styleSheetId, contentToRevertTo, callback.bind(this)); } } @@ -348,7 +348,7 @@ WebInspector.CSSStyleDeclaration.prototype = { } } - InspectorBackend.setPropertyText2(this.id, index, name + ": " + value + ";", false, callback.bind(null, userCallback)); + InspectorBackend.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(null, userCallback)); }, appendProperty: function(name, value, userCallback) @@ -488,7 +488,7 @@ WebInspector.CSSProperty.prototype = { throw "No ownerStyle for property"; // An index past all the properties adds a new property to the style. - InspectorBackend.setPropertyText2(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this)); + InspectorBackend.setPropertyText(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this)); }, setValue: function(newValue, userCallback) @@ -517,7 +517,7 @@ WebInspector.CSSProperty.prototype = { } } - InspectorBackend.toggleProperty2(this.ownerStyle.id, this.index, disabled, callback.bind(this)); + InspectorBackend.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this)); } } @@ -548,7 +548,7 @@ WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback) else userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload)); } - InspectorBackend.getStyleSheet2(styleSheetId, callback.bind(this)); + InspectorBackend.getStyleSheet(styleSheetId, callback.bind(this)); } WebInspector.CSSStyleSheet.prototype = { @@ -569,6 +569,6 @@ WebInspector.CSSStyleSheet.prototype = { } } - InspectorBackend.setStyleSheetText2(this.id, newText, callback.bind(this)); + InspectorBackend.setStyleSheetText(this.id, newText, callback.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/ChangesView.js b/Source/WebCore/inspector/front-end/ChangesView.js deleted file mode 100644 index 5ab6942..0000000 --- a/Source/WebCore/inspector/front-end/ChangesView.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2009 Joseph Pecoraro - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.ChangesView = function(drawer) -{ - WebInspector.View.call(this); - this.element.innerHTML = "<div style=\"bottom:25%;color:rgb(192,192,192);font-size:12px;height:65px;left:0px;margin:auto;position:absolute;right:0px;text-align:center;top:0px;\"><h1>Not Implemented Yet</h1></div>"; - - this.drawer = drawer; - - this.clearButton = document.createElement("button"); - this.clearButton.id = "clear-changes-status-bar-item"; - this.clearButton.title = WebInspector.UIString("Clear changes log."); - this.clearButton.className = "status-bar-item clear-status-bar-item"; - this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false); - - this.toggleChangesButton = document.getElementById("changes-status-bar-item"); - this.toggleChangesButton.title = WebInspector.UIString("Show changes view."); - this.toggleChangesButton.addEventListener("click", this._toggleChangesButtonClicked.bind(this), false); - var anchoredStatusBar = document.getElementById("anchored-status-bar-items"); - anchoredStatusBar.appendChild(this.toggleChangesButton); -} - -WebInspector.ChangesView.prototype = { - _clearButtonClicked: function() - { - // Not Implemented Yet - }, - - _toggleChangesButtonClicked: function() - { - this.drawer.visibleView = this; - }, - - attach: function(mainElement, statusBarElement) - { - mainElement.appendChild(this.element); - statusBarElement.appendChild(this.clearButton); - }, - - show: function() - { - this.toggleChangesButton.addStyleClass("toggled-on"); - this.toggleChangesButton.title = WebInspector.UIString("Hide changes view."); - }, - - hide: function() - { - this.toggleChangesButton.removeStyleClass("toggled-on"); - this.toggleChangesButton.title = WebInspector.UIString("Show changes view."); - } -} - -WebInspector.ChangesView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/Source/WebCore/inspector/front-end/ConsoleView.js b/Source/WebCore/inspector/front-end/ConsoleView.js index bd08e60..35d1ebf 100644 --- a/Source/WebCore/inspector/front-end/ConsoleView.js +++ b/Source/WebCore/inspector/front-end/ConsoleView.js @@ -89,7 +89,7 @@ WebInspector.ConsoleView = function(drawer) this.filter(this.allElement, false); this._registerShortcuts(); - this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); + this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false); this._customFormatters = { "object": this._formatobject, @@ -150,11 +150,6 @@ WebInspector.ConsoleView.prototype = { { console.clearMessages(); }, - - monitoringXHRStateChanged: function(enabled) - { - console._monitoringXHREnabled = enabled; - } } InspectorBackend.registerDomainDispatcher("Console", dispatcher); }, @@ -278,6 +273,7 @@ WebInspector.ConsoleView.prototype = { if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebInspector.ConsoleCommandResult)) { this._incrementErrorWarningCount(msg); WebInspector.resourceTreeModel.addConsoleMessage(msg); + WebInspector.panels.scripts.addConsoleMessage(msg); this.commandSincePreviousMessage = false; this.previousMessage = msg; } else if (msg instanceof WebInspector.ConsoleCommand) { @@ -326,6 +322,7 @@ WebInspector.ConsoleView.prototype = { clearMessages: function() { WebInspector.resourceTreeModel.clearConsoleMessages(); + WebInspector.panels.scripts.clearConsoleMessages(); this.messages = []; @@ -359,12 +356,12 @@ WebInspector.ConsoleView.prototype = { var reportCompletions = this._reportCompletions.bind(this, bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix); // Collect comma separated object properties for the completion. - var includeInspectorCommandLineAPI = (!dotNotation && !bracketNotation); + var includeCommandLineAPI = (!dotNotation && !bracketNotation); var injectedScriptAccess; if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) - InspectorBackend.getCompletionsOnCallFrame(WebInspector.panels.scripts.selectedCallFrameId(), expressionString, includeInspectorCommandLineAPI, reportCompletions); + InspectorBackend.getCompletionsOnCallFrame(WebInspector.panels.scripts.selectedCallFrameId(), expressionString, includeCommandLineAPI, reportCompletions); else - InspectorBackend.getCompletions(expressionString, includeInspectorCommandLineAPI, reportCompletions); + InspectorBackend.getCompletions(expressionString, includeCommandLineAPI, reportCompletions); }, _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) { @@ -418,9 +415,12 @@ WebInspector.ConsoleView.prototype = { return; } - var itemAction = InspectorBackend.setMonitoringXHREnabled.bind(InspectorBackend, !this._monitoringXHREnabled); + var itemAction = function () { + WebInspector.settings.monitoringXHREnabled = !WebInspector.settings.monitoringXHREnabled; + InspectorBackend.setMonitoringXHREnabled(WebInspector.settings.monitoringXHREnabled); + }.bind(this); var contextMenu = new WebInspector.ContextMenu(); - contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), itemAction, this._monitoringXHREnabled); + contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), itemAction, WebInspector.settings.monitoringXHREnabled) contextMenu.appendItem(WebInspector.UIString("Clear Console"), this.requestClearMessages.bind(this)); contextMenu.show(event); }, @@ -510,17 +510,13 @@ WebInspector.ConsoleView.prototype = { } }, - evalInInspectedWindow: function(expression, objectGroup, callback) + evalInInspectedWindow: function(expression, objectGroup, includeCommandLineAPI, callback) { if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) { - WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, objectGroup, callback); + WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, objectGroup, includeCommandLineAPI, callback); return; } - this.doEvalInWindow(expression, objectGroup, callback); - }, - doEvalInWindow: function(expression, objectGroup, callback) - { if (!expression) { // There is no expression, so the completion should happen against global properties. expression = "this"; @@ -530,7 +526,7 @@ WebInspector.ConsoleView.prototype = { { callback(WebInspector.RemoteObject.fromPayload(result)); } - InspectorBackend.evaluate(expression, objectGroup, evalCallback); + InspectorBackend.evaluate(expression, objectGroup, includeCommandLineAPI, evalCallback); }, _enterKeyPressed: function(event) @@ -561,7 +557,7 @@ WebInspector.ConsoleView.prototype = { self.addMessage(new WebInspector.ConsoleCommandResult(result, commandMessage)); } - this.evalInInspectedWindow(str, "console", printResult); + this.evalInInspectedWindow(str, "console", true, printResult); }, _format: function(output, forceObjectFormat) diff --git a/Source/WebCore/inspector/front-end/ContextMenu.js b/Source/WebCore/inspector/front-end/ContextMenu.js index 47045a2..58810fb 100644 --- a/Source/WebCore/inspector/front-end/ContextMenu.js +++ b/Source/WebCore/inspector/front-end/ContextMenu.js @@ -44,6 +44,7 @@ WebInspector.ContextMenu.prototype = { WebInspector._contextMenu = this; InspectorFrontendHost.showContextMenu(event, this._items); } + event.stopPropagation(); }, appendItem: function(label, handler, disabled) diff --git a/Source/WebCore/inspector/front-end/DOMAgent.js b/Source/WebCore/inspector/front-end/DOMAgent.js index e4fc7ad..3645bb9 100644 --- a/Source/WebCore/inspector/front-end/DOMAgent.js +++ b/Source/WebCore/inspector/front-end/DOMAgent.js @@ -502,19 +502,19 @@ WebInspector.ApplicationCacheDispatcher = function() { } -WebInspector.ApplicationCacheDispatcher.prototype = { - getApplicationCachesAsync: function(callback) +WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync = function(callback) +{ + function mycallback(applicationCaches) { - function mycallback(applicationCaches) - { - // FIXME: Currently, this list only returns a single application cache. - if (applicationCaches) - callback(applicationCaches); - } - - InspectorBackend.getApplicationCaches(mycallback); - }, - + // FIXME: Currently, this list only returns a single application cache. + if (applicationCaches) + callback(applicationCaches); + } + + InspectorBackend.getApplicationCaches(mycallback); +} + +WebInspector.ApplicationCacheDispatcher.prototype = { updateApplicationCacheStatus: function(status) { WebInspector.panels.resources.updateApplicationCacheStatus(status); diff --git a/Source/WebCore/inspector/front-end/DataGrid.js b/Source/WebCore/inspector/front-end/DataGrid.js index 5831d1e..45f0b55 100644 --- a/Source/WebCore/inspector/front-end/DataGrid.js +++ b/Source/WebCore/inspector/front-end/DataGrid.js @@ -493,6 +493,11 @@ WebInspector.DataGrid.prototype = { this._columnWidthsInitialized = false; }, + get scrollContainer() + { + return this._scrollContainer; + }, + isScrolledToLastRow: function() { return this._scrollContainer.isScrolledToBottom(); diff --git a/Source/WebCore/inspector/front-end/DebuggerModel.js b/Source/WebCore/inspector/front-end/DebuggerModel.js index 717486c..1bf1e47 100644 --- a/Source/WebCore/inspector/front-end/DebuggerModel.js +++ b/Source/WebCore/inspector/front-end/DebuggerModel.js @@ -33,7 +33,6 @@ WebInspector.DebuggerModel = function() this._paused = false; this._callFrames = []; this._breakpoints = {}; - this._sourceIDAndLineToBreakpointId = {}; this._scripts = {}; InspectorBackend.registerDomainDispatcher("Debugger", new WebInspector.DebuggerDispatcher(this)); @@ -46,64 +45,116 @@ WebInspector.DebuggerModel.Events = { FailedToParseScriptSource: "failed-to-parse-script-source", ScriptSourceChanged: "script-source-changed", BreakpointAdded: "breakpoint-added", - BreakpointRemoved: "breakpoint-removed" + BreakpointRemoved: "breakpoint-removed", + BreakpointResolved: "breakpoint-resolved" } WebInspector.DebuggerModel.prototype = { + enableDebugger: function() + { + InspectorBackend.enableDebugger(); + if (this._breakpointsPushedToBackend) + return; + var breakpoints = WebInspector.settings.breakpoints; + for (var i = 0; i < breakpoints.length; ++i) { + var breakpoint = breakpoints[i]; + if (typeof breakpoint.url !== "string" || typeof breakpoint.lineNumber !== "number" || typeof breakpoint.columnNumber !== "number" || + typeof breakpoint.condition !== "string" || typeof breakpoint.enabled !== "boolean") + continue; + this.setBreakpoint(breakpoint.url, breakpoint.lineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled); + } + this._breakpointsPushedToBackend = true; + }, + + disableDebugger: function() + { + InspectorBackend.disableDebugger(); + }, + continueToLine: function(sourceID, lineNumber) { - function didSetBreakpoint(breakpointId, actualLineNumber) + InspectorBackend.continueToLocation(sourceID, lineNumber, 0); + }, + + setBreakpoint: function(url, lineNumber, columnNumber, condition, enabled) + { + function didSetBreakpoint(breakpointsPushedToBackend, breakpointId, locations) { if (!breakpointId) return; - if (this.findBreakpoint(sourceID, actualLineNumber)) { - InspectorBackend.removeBreakpoint(breakpointId); - return; - } - if ("_continueToLineBreakpointId" in this) - InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId); - this._continueToLineBreakpointId = breakpointId; + var breakpoint = new WebInspector.Breakpoint(breakpointId, url, "", lineNumber, columnNumber, condition, enabled); + breakpoint.locations = locations; + this._breakpoints[breakpointId] = breakpoint; + if (breakpointsPushedToBackend) + this._saveBreakpoints(); + this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint); } - InspectorBackend.setBreakpoint(sourceID, lineNumber, "", true, didSetBreakpoint.bind(this)); - if (this._paused) - InspectorBackend.resume(); + InspectorBackend.setJavaScriptBreakpoint(url, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this, this._breakpointsPushedToBackend)); }, - setBreakpoint: function(sourceID, lineNumber, enabled, condition) + setBreakpointBySourceId: function(sourceID, lineNumber, columnNumber, condition, enabled) { - function didSetBreakpoint(breakpointId, actualLineNumber) + function didSetBreakpoint(breakpointId, actualLineNumber, actualColumnNumber) { - if (breakpointId) - this._breakpointSetOnBackend(breakpointId, sourceID, actualLineNumber, condition, enabled, lineNumber, false); + if (!breakpointId) + return; + var breakpoint = new WebInspector.Breakpoint(breakpointId, "", sourceID, lineNumber, columnNumber, condition, enabled); + breakpoint.addLocation(sourceID, actualLineNumber, actualColumnNumber); + this._breakpoints[breakpointId] = breakpoint; + this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint); } - InspectorBackend.setBreakpoint(sourceID, lineNumber, condition, enabled, didSetBreakpoint.bind(this)); + InspectorBackend.setJavaScriptBreakpointBySourceId(sourceID, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this)); }, removeBreakpoint: function(breakpointId) { - InspectorBackend.removeBreakpoint(breakpointId); + InspectorBackend.removeJavaScriptBreakpoint(breakpointId); var breakpoint = this._breakpoints[breakpointId]; delete this._breakpoints[breakpointId]; - delete this._sourceIDAndLineToBreakpointId[this._encodeSourceIDAndLine(breakpoint.sourceID, breakpoint.line)]; + this._saveBreakpoints(); this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointRemoved, breakpointId); - breakpoint.dispatchEventToListeners("removed"); }, - _breakpointSetOnBackend: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, restored) + updateBreakpoint: function(breakpointId, condition, enabled) { - var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber); - if (sourceIDAndLine in this._sourceIDAndLineToBreakpointId) { - InspectorBackend.removeBreakpoint(breakpointId); + var breakpoint = this._breakpoints[breakpointId]; + this.removeBreakpoint(breakpointId); + if (breakpoint.url) + this.setBreakpoint(breakpoint.url, breakpoint.lineNumber, breakpoint.columnNumber, condition, enabled); + else + this.setBreakpointBySourceId(breakpoint.sourceID, breakpoint.lineNumber, breakpoint.columnNumber, condition, enabled); + }, + + _breakpointResolved: function(breakpointId, sourceID, lineNumber, columnNumber) + { + var breakpoint = this._breakpoints[breakpointId]; + if (!breakpoint) return; + breakpoint.addLocation(sourceID, lineNumber, columnNumber); + this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, breakpoint); + }, + + _saveBreakpoints: function() + { + var serializedBreakpoints = []; + for (var id in this._breakpoints) { + var breakpoint = this._breakpoints[id]; + if (!breakpoint.url) + continue; + var serializedBreakpoint = {}; + serializedBreakpoint.url = breakpoint.url; + serializedBreakpoint.lineNumber = breakpoint.lineNumber; + serializedBreakpoint.columnNumber = breakpoint.columnNumber; + serializedBreakpoint.condition = breakpoint.condition; + serializedBreakpoint.enabled = breakpoint.enabled; + serializedBreakpoints.push(serializedBreakpoint); } + WebInspector.settings.breakpoints = serializedBreakpoints; + }, - var url = this._scripts[sourceID].sourceURL; - var breakpoint = new WebInspector.Breakpoint(this, breakpointId, sourceID, url, lineNumber, enabled, condition); - breakpoint.restored = restored; - breakpoint.originalLineNumber = originalLineNumber; - this._breakpoints[breakpointId] = breakpoint; - this._sourceIDAndLineToBreakpointId[sourceIDAndLine] = breakpointId; - this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint); + get breakpoints() + { + return this._breakpoints; }, breakpointForId: function(breakpointId) @@ -124,23 +175,26 @@ WebInspector.DebuggerModel.prototype = { findBreakpoint: function(sourceID, lineNumber) { - var sourceIDAndLine = this._encodeSourceIDAndLine(sourceID, lineNumber); - var breakpointId = this._sourceIDAndLineToBreakpointId[sourceIDAndLine]; - return this._breakpoints[breakpointId]; - }, - - _encodeSourceIDAndLine: function(sourceID, lineNumber) - { - return sourceID + ":" + lineNumber; + for (var id in this._breakpoints) { + var locations = this._breakpoints[id].locations; + for (var i = 0; i < locations.length; ++i) { + if (locations[i].sourceID == sourceID && locations[i].lineNumber + 1 === lineNumber) + return this._breakpoints[id]; + } + } }, reset: function() { this._paused = false; this._callFrames = []; - this._breakpoints = {}; - delete this._oneTimeBreakpoint; - this._sourceIDAndLineToBreakpointId = {}; + for (var id in this._breakpoints) { + var breakpoint = this._breakpoints[id]; + if (!breakpoint.url) + this.removeBreakpoint(id); + else + breakpoint.locations = []; + } this._scripts = {}; }, @@ -189,10 +243,15 @@ WebInspector.DebuggerModel.prototype = { var diff = Array.diff(oldSource.split("\n"), script.source.split("\n")); for (var id in this._breakpoints) { var breakpoint = this._breakpoints[id]; - if (breakpoint.sourceID !== sourceID) - continue; - breakpoint.remove(); - var lineNumber = breakpoint.line - 1; + if (breakpoint.url) { + if (breakpoint.url !== script.sourceURL) + continue; + } else { + if (breakpoint.sourceID !== sourceID) + continue; + } + this.removeBreakpoint(breakpoint.id); + var lineNumber = breakpoint.lineNumber; var newLineNumber = diff.left[lineNumber].row; if (newLineNumber === undefined) { for (var i = lineNumber - 1; i >= 0; --i) { @@ -207,8 +266,12 @@ WebInspector.DebuggerModel.prototype = { break; } } - if (newLineNumber !== undefined) - this.setBreakpoint(sourceID, newLineNumber + 1, breakpoint.enabled, breakpoint.condition); + if (newLineNumber === undefined) + continue; + if (breakpoint.url) + this.setBreakpoint(breakpoint.url, newLineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled); + else + this.setBreakpointBySourceId(sourceID, newLineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled); } this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ScriptSourceChanged, { sourceID: sourceID, oldSource: oldSource }); @@ -223,10 +286,6 @@ WebInspector.DebuggerModel.prototype = { { this._paused = true; this._callFrames = details.callFrames; - if ("_continueToLineBreakpointId" in this) { - InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId); - delete this._continueToLineBreakpointId; - } this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details); }, @@ -241,7 +300,7 @@ WebInspector.DebuggerModel.prototype = { { var script = new WebInspector.Script(sourceID, sourceURL, "", lineOffset, columnOffset, length, undefined, undefined, scriptWorldType); this._scripts[sourceID] = script; - this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, sourceID); + this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, script); }, _failedToParseScriptSource: function(sourceURL, source, startingLine, errorLine, errorMessage) @@ -295,9 +354,9 @@ WebInspector.DebuggerDispatcher.prototype = { this._debuggerModel._failedToParseScriptSource(sourceURL, source, startingLine, errorLine, errorMessage); }, - breakpointResolved: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber) + breakpointResolved: function(breakpointId, sourceID, lineNumber, columnNumber) { - this._debuggerModel._breakpointSetOnBackend(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, true); + this._debuggerModel._breakpointResolved(breakpointId, sourceID, lineNumber, columnNumber); }, didCreateWorker: function() diff --git a/Source/WebCore/inspector/front-end/DetailedHeapshotView.js b/Source/WebCore/inspector/front-end/DetailedHeapshotView.js new file mode 100644 index 0000000..5291bf2 --- /dev/null +++ b/Source/WebCore/inspector/front-end/DetailedHeapshotView.js @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.DetailedHeapshotView = function(parent, profile) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("heap-snapshot-view"); + + this.parent = parent; + this.profile = profile; +} + +WebInspector.DetailedHeapshotView.prototype = { + get profile() + { + return this._profile; + }, + + set profile(profile) + { + this._profile = profile; + } +}; + +WebInspector.DetailedHeapshotView.prototype.__proto__ = WebInspector.View.prototype; + +WebInspector.DetailedHeapshotProfileType = function() +{ + WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("HEAP SNAPSHOTS")); +} + +WebInspector.DetailedHeapshotProfileType.prototype = { + get buttonTooltip() + { + return WebInspector.UIString("Take heap snapshot."); + }, + + get buttonStyle() + { + return "heap-snapshot-status-bar-item status-bar-item"; + }, + + buttonClicked: function() + { + WebInspector.panels.profiles.takeHeapSnapshot(true); + }, + + get welcomeMessage() + { + return WebInspector.UIString("Get a heap snapshot by pressing the %s button on the status bar."); + }, + + createSidebarTreeElementForProfile: function(profile) + { + return new WebInspector.ProfileSidebarTreeElement(profile, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item"); + }, + + createView: function(profile) + { + return new WebInspector.DetailedHeapshotView(WebInspector.panels.profiles, profile); + } +} + +WebInspector.DetailedHeapshotProfileType.prototype.__proto__ = WebInspector.ProfileType.prototype; diff --git a/Source/WebCore/inspector/front-end/Drawer.js b/Source/WebCore/inspector/front-end/Drawer.js index 3f827fb..4861c90 100644 --- a/Source/WebCore/inspector/front-end/Drawer.js +++ b/Source/WebCore/inspector/front-end/Drawer.js @@ -35,11 +35,11 @@ WebInspector.Drawer = function() this.state = WebInspector.Drawer.State.Hidden; this.fullPanel = false; - this.mainElement = document.getElementById("main"); - this.toolbarElement = document.getElementById("toolbar"); - this.mainStatusBar = document.getElementById("main-status-bar"); - this.mainStatusBar.addEventListener("mousedown", this._startStatusBarDragging.bind(this), true); - this.viewStatusBar = document.getElementById("other-drawer-status-bar-items"); + this._mainElement = document.getElementById("main"); + this._toolbarElement = document.getElementById("toolbar"); + this._mainStatusBar = document.getElementById("main-status-bar"); + this._mainStatusBar.addEventListener("mousedown", this._startStatusBarDragging.bind(this), true); + this._viewStatusBar = document.getElementById("other-drawer-status-bar-items"); this._counters = document.getElementById("counters"); this._drawerStatusBar = document.getElementById("drawer-status-bar"); } @@ -67,8 +67,8 @@ WebInspector.Drawer.prototype = { if (x && !firstTime) { this._safelyRemoveChildren(); - this.viewStatusBar.removeChildren(); // optimize this? call old.detach() - x.attach(this.element, this.viewStatusBar); + this._viewStatusBar.removeChildren(); // optimize this? call old.detach() + x.attach(this.element, this._viewStatusBar); x.show(); this.visible = true; } @@ -77,7 +77,7 @@ WebInspector.Drawer.prototype = { get savedHeight() { var height = this._savedHeight || this.element.offsetHeight; - return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this.mainElement.totalOffsetTop - Preferences.minConsoleHeight); + return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop - Preferences.minConsoleHeight); }, showView: function(view) @@ -101,16 +101,15 @@ WebInspector.Drawer.prototype = { document.body.addStyleClass("drawer-visible"); var anchoredItems = document.getElementById("anchored-status-bar-items"); - var height = (this.fullPanel ? window.innerHeight - this.toolbarElement.offsetHeight : this.savedHeight); + var height = (this.fullPanel ? window.innerHeight - this._toolbarElement.offsetHeight : this.savedHeight); var animations = [ {element: this.element, end: {height: height}}, - {element: document.getElementById("main"), end: {bottom: height}}, - {element: document.getElementById("main-status-bar"), start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}}, - {element: document.getElementById("other-drawer-status-bar-items"), start: {opacity: 0}, end: {opacity: 1}} + {element: this._mainElement, end: {bottom: height}}, + {element: this._mainStatusBar, start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}}, + {element: this._viewStatusBar, start: {opacity: 0}, end: {opacity: 1}} ]; - var drawerStatusBar = document.getElementById("drawer-status-bar"); - drawerStatusBar.insertBefore(anchoredItems, drawerStatusBar.firstChild); + this._drawerStatusBar.insertBefore(anchoredItems, this._drawerStatusBar.firstChild); if (this._currentPanelCounters) { var oldRight = this._drawerStatusBar.clientWidth - (this._counters.offsetLeft + this._currentPanelCounters.offsetWidth); @@ -118,7 +117,7 @@ WebInspector.Drawer.prototype = { var rightPadding = (oldRight - newRight); animations.push({element: this._currentPanelCounters, start: {"padding-right": rightPadding}, end: {"padding-right": 0}}); this._currentPanelCounters.parentNode.removeChild(this._currentPanelCounters); - this.mainStatusBar.appendChild(this._currentPanelCounters); + this._mainStatusBar.appendChild(this._currentPanelCounters); } function animationFinished() @@ -128,13 +127,13 @@ WebInspector.Drawer.prototype = { if (this.visibleView.afterShow) this.visibleView.afterShow(); delete this._animating; - delete this._currentAnimationInterval; + delete this._currentAnimation; this.state = (this.fullPanel ? WebInspector.Drawer.State.Full : WebInspector.Drawer.State.Variable); if (this._currentPanelCounters) this._currentPanelCounters.removeAttribute("style"); } - this._currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); + this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); }, hide: function() @@ -159,21 +158,21 @@ WebInspector.Drawer.prototype = { // Temporarily set properties and classes to mimic the post-animation values so panels // like Elements in their updateStatusBarItems call will size things to fit the final location. - this.mainStatusBar.style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px"); + this._mainStatusBar.style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px"); document.body.removeStyleClass("drawer-visible"); if ("updateStatusBarItems" in WebInspector.currentPanel) WebInspector.currentPanel.updateStatusBarItems(); document.body.addStyleClass("drawer-visible"); var animations = [ - {element: document.getElementById("main"), end: {bottom: 0}}, - {element: document.getElementById("main-status-bar"), start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}}, - {element: document.getElementById("other-drawer-status-bar-items"), start: {opacity: 1}, end: {opacity: 0}} + {element: this._mainElement, end: {bottom: 0}}, + {element: this._mainStatusBar, start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}}, + {element: this._viewStatusBar, start: {opacity: 1}, end: {opacity: 0}} ]; if (this._currentPanelCounters) { var newRight = this._drawerStatusBar.clientWidth - this._counters.offsetLeft; - var oldRight = this.mainStatusBar.clientWidth - (this._currentPanelCounters.offsetLeft + this._currentPanelCounters.offsetWidth); + var oldRight = this._mainStatusBar.clientWidth - (this._currentPanelCounters.offsetLeft + this._currentPanelCounters.offsetWidth); var rightPadding = (newRight - oldRight); animations.push({element: this._currentPanelCounters, start: {"padding-right": 0}, end: {"padding-right": rightPadding}}); } @@ -181,9 +180,8 @@ WebInspector.Drawer.prototype = { function animationFinished() { WebInspector.currentPanel.resize(); - var mainStatusBar = document.getElementById("main-status-bar"); - mainStatusBar.insertBefore(anchoredItems, mainStatusBar.firstChild); - mainStatusBar.style.removeProperty("padding-left"); + this._mainStatusBar.insertBefore(anchoredItems, this._mainStatusBar.firstChild); + this._mainStatusBar.style.removeProperty("padding-left"); if (this._currentPanelCounters) { this._currentPanelCounters.setAttribute("style", null); @@ -193,11 +191,11 @@ WebInspector.Drawer.prototype = { document.body.removeStyleClass("drawer-visible"); delete this._animating; - delete this._currentAnimationInterval; + delete this._currentAnimation; this.state = WebInspector.Drawer.State.Hidden; } - this._currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); + this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); }, resize: function() @@ -206,14 +204,13 @@ WebInspector.Drawer.prototype = { return; var height; - var mainElement = document.getElementById("main"); if (this.state === WebInspector.Drawer.State.Variable) { height = parseInt(this.element.style.height); - height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight); + height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop - Preferences.minConsoleHeight); } else - height = window.innerHeight - this.toolbarElement.offsetHeight; + height = window.innerHeight - this._toolbarElement.offsetHeight; - mainElement.style.bottom = height + "px"; + this._mainElement.style.bottom = height + "px"; this.element.style.height = height + "px"; }, @@ -224,7 +221,7 @@ WebInspector.Drawer.prototype = { if (this.visible) { this._savedHeight = this.element.offsetHeight; - var height = window.innerHeight - this.toolbarElement.offsetHeight; + var height = window.innerHeight - this._toolbarElement.offsetHeight; this._animateDrawerHeight(height, WebInspector.Drawer.State.Full); } }, @@ -249,6 +246,12 @@ WebInspector.Drawer.prototype = { this.fullPanel = false; }, + immediatelyFinishAnimation: function() + { + if (this._currentAnimation) + this._currentAnimation.forceComplete(); + }, + set currentPanelCounters(x) { if (!x) { @@ -260,7 +263,7 @@ WebInspector.Drawer.prototype = { this._currentPanelCounters = x; if (this.visible) - this.mainStatusBar.appendChild(x); + this._mainStatusBar.appendChild(x); else this._counters.insertBefore(x, this._counters.firstChild); }, @@ -268,9 +271,10 @@ WebInspector.Drawer.prototype = { _cancelAnimationIfNeeded: function() { if (this._animating) { - clearInterval(this._currentAnimationInterval); + if (this._currentAnimation) + this._currentAnimation.cancel(); delete this._animating; - delete this._currentAnimationInterval; + delete this._currentAnimation; } }, @@ -279,17 +283,17 @@ WebInspector.Drawer.prototype = { this._animating = true; var animations = [ {element: this.element, end: {height: height}}, - {element: document.getElementById("main"), end: {bottom: height}} + {element: this._mainElement, end: {bottom: height}} ]; function animationFinished() { delete this._animating; - delete this._currentAnimationInterval; + delete this._currentAnimation; this.state = finalState; } - this._currentAnimationInterval = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); + this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(), animationFinished.bind(this)); }, _animationDuration: function() @@ -316,10 +320,10 @@ WebInspector.Drawer.prototype = { _startStatusBarDragging: function(event) { - if (!this.visible || event.target !== this.mainStatusBar) + if (!this.visible || event.target !== this._mainStatusBar) return; - WebInspector.elementDragStart(this.mainStatusBar, this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize"); + WebInspector.elementDragStart(this._mainStatusBar, this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize"); this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop; @@ -328,11 +332,10 @@ WebInspector.Drawer.prototype = { _statusBarDragging: function(event) { - var mainElement = document.getElementById("main"); var height = window.innerHeight - event.pageY + this._statusBarDragOffset; - height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - mainElement.totalOffsetTop - Preferences.minConsoleHeight); + height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop - Preferences.minConsoleHeight); - mainElement.style.bottom = height + "px"; + this._mainElement.style.bottom = height + "px"; this.element.style.height = height + "px"; event.preventDefault(); diff --git a/Source/WebCore/inspector/front-end/ElementsPanel.js b/Source/WebCore/inspector/front-end/ElementsPanel.js index 9299479..e6af93c 100644 --- a/Source/WebCore/inspector/front-end/ElementsPanel.js +++ b/Source/WebCore/inspector/front-end/ElementsPanel.js @@ -255,13 +255,20 @@ WebInspector.ElementsPanel.prototype = { return false; // Add resource-related actions. - // Keep these consistent with those added in WebInspector.StylesSidebarPane.prototype._populateHrefContextMenu(). - contextMenu.appendItem(WebInspector.UIString("Open Link in New Window"), WebInspector.openResource.bind(null, resourceURL, false)); + contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(null, resourceURL, false)); if (WebInspector.resourceForURL(resourceURL)) contextMenu.appendItem(WebInspector.UIString("Open Link in Resources Panel"), WebInspector.openResource.bind(null, resourceURL, true)); return true; }, + switchToAndFocus: function(node) + { + // Reset search restore. + WebInspector.cancelSearch(); + WebInspector.currentPanel = this; + this.focusedDOMNode = node; + }, + _updateMatchesCount: function() { WebInspector.updateSearchMatchesCount(this._searchResults.length, this); diff --git a/Source/WebCore/inspector/front-end/ElementsTreeOutline.js b/Source/WebCore/inspector/front-end/ElementsTreeOutline.js index 722c028..56c3e75 100644 --- a/Source/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/Source/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -268,8 +268,7 @@ WebInspector.ElementsTreeOutline.prototype = { if (this.showInElementsPanelEnabled) { function focusElement() { - WebInspector.currentPanel = WebInspector.panels.elements; - WebInspector.panels.elements.focusedDOMNode = listItem.treeElement.representedObject; + WebInspector.panels.elements.switchToAndFocus(listItem.treeElement.representedObject); } contextMenu.appendItem(WebInspector.UIString("Reveal in Elements Panel"), focusElement.bind(this)); } else { diff --git a/Source/WebCore/inspector/front-end/ExtensionAPI.js b/Source/WebCore/inspector/front-end/ExtensionAPI.js index b10452d..6a11d62 100644 --- a/Source/WebCore/inspector/front-end/ExtensionAPI.js +++ b/Source/WebCore/inspector/front-end/ExtensionAPI.js @@ -387,9 +387,9 @@ function InspectedWindow() } InspectedWindow.prototype = { - reload: function() + reload: function(userAgent) { - return extensionServer.sendRequest({ command: "reload" }); + return extensionServer.sendRequest({ command: "reload", userAgent: userAgent }); }, eval: function(expression, callback) diff --git a/Source/WebCore/inspector/front-end/ExtensionAPISchema.json b/Source/WebCore/inspector/front-end/ExtensionAPISchema.json new file mode 100755 index 0000000..28084ba --- /dev/null +++ b/Source/WebCore/inspector/front-end/ExtensionAPISchema.json @@ -0,0 +1,513 @@ +[ + { + "namespace": "experimental.webInspector.inspectedWindow", + "description": "Provides access to the window being inspected.", + "functions": [ + { + "name": "eval", + "type": "function", + "description": "Evaluates a JavaScript expression in the context of inspected page (NOTE: the expression must evaluate to a JSON-compliant object, otherwise the exception is thrown)", + "parameters": [ + { + "name": "expression", + "type": "string", + "description": "An expression to evaluate." + }, + { + "name": "callback", + "type": "function", + "description": "A function called when evaluation completes.", + "parameters": [ + { + "name": "result", + "type": "object", + "description": "The result of evaluation" + }, + { + "name": "isException", + "type": "boolean", + "description": "Set if an exception was caught while evaluating the expression" + } + ] + } + ] + } + ], + "events": [ + { + "name": "onDOMContentLoaded", + "type": "function", + "description": "Fired after DOMContentLoaded event on inspected page is fired." + }, + { + "name": "onLoaded", + "type": "function", + "description": "Fired after load event on inspected page is fired." + }, + { + "name": "onNavigated", + "type": "function", + "description": "Fired when navigation occurs in the window being inspected." + } + ] + }, + { + "namespace": "experimental.webInspector.panels", + "types": [ + { + "id": "PanelWithSidebars", + "type": "object", + "isInstanceOf": "Panel", + "description": "A panel within Web Inspector UI that has sidebars.", + "functions": [ + { + "name": "createSidebarPane", + "type": "function", + "description": "Creates a pane within panel's sidebar.", + "parameters": [ + { + "name": "title", + "type": "string", + "description": "A text that is displayed in sidebar caption." + }, + { + "name": "url", + "type": "string", + "description": "An URL of the page that represents the sidebar." + }, + { + "name": "callback", + "type": "function", + "description": "A callback invoked when sidebar is created", + "parameters": [ + { + "name": "result", + "description": "An ExtensionSidebarPane object for created sidebar pane", + "$ref": "ExtensionSidebarPane" + } + ] + } + ] + }, + { + "name": "createWatchExpressionSidebarPane", + "type": "function", + "description": "Creates a pane with an object property tree (similar to a watch sidebar pane).", + "parameters": [ + { + "name": "title", + "type": "string", + "description": "A text that is displayed in sidebar caption." + }, + { + "name": "callback", + "type": "function", + "description": "A callback invoked when sidebar is created", + "parameters": [ + { + "name": "result", + "description": "A WatchExpressionSidebarPane object for created sidebar pane", + "$ref": "WatchExpressionSidebarPane" + } + ] + } + ] + } + ] + }, + { + "id": "ElementsPanel", + "type": "object", + "isInstanceOf": "PanelWithSidebars", + "description": "Represents Elements panel", + "events": [ + { + "name": "onSelectionChanged", + "description": "Fired when an objects is selected in the panel." + } + ] + }, + { + "id": "ExtensionPanel", + "type": "object", + "isInstanceOf": "Panel", + "description": "Represents a panel created by extension", + "events": [ + { + "name": "onSearch", + "description": "Fired upon a search action (start of a new search, search result navigation or search being canceled).", + "parameters": [ + { + "name": "action", + "type": "string", + "description": "Type of search action being performed." + }, + { + "name": "queryString", + "type": "string", + "optional": true, + "description": "Query string (only for 'performSearch')" + } + ] + } + ] + }, + { + "id": "ExtensionSidebarPane", + "type": "object", + "description": "A sidebar created by the extension.", + "functions": [ + { + "name": "setHeight", + "type": "function", + "description": "Sets the height of the sidebar.", + "parameters": [ + { + "name": "height", + "type": "string", + "description": "A CSS-like size specification, e.g. '10px' or '12pt'" + } + ] + } + ] + }, + { + "id": "WatchExpressionSidebarPane", + "type": "object", + "description": "A sidebar created by the extension.", + "functions": [ + { + "name": "setHeight", + "type": "function", + "description": "Sets the height of the sidebar.", + "parameters": [ + { + "name": "height", + "type": "string", + "description": "A CSS-like size specification, e.g. '10px' or '12pt'" + } + ] + }, + { + "name": "setExpression", + "type": "function", + "description": "Sets an expression that is evaluated within the inspected page. The result is displayed in the sidebar pane.", + "parameters": [ + { + "name": "expression", + "type": "string", + "description": "An expression to be evaluated in context of the inspected page. JavaScript objects and DOM nodes are displayed in an expandable tree similar to the console/watch." + }, + { + "name": "rootTitle", + "type": "string", + "optional": true, + "description": "An optional title for the root of the expression tree." + } + ] + }, + { + "name": "setObject", + "type": "function", + "description": "Sets a JSON-compliant object to be displayed in the sidebar pane.", + "parameters": [ + { + "name": "jsonObject", + "type": "string", + "description": "An object to be displayed in context of the inspected page. Evaluated in the context of the caller (API client)." + }, + { + "name": "rootTitle", + "type": "string", + "optional": true, + "description": "An optional title for the root of the expression tree." + } + ] + } + ] + } + ], + "properties": { + "scripts": { + "$ref": "ScriptsPanel", + "description": "Scripts panel" + } + }, + "functions": [ + { + "name": "create", + "type": "function", + "description": "Creates an extension panel.", + "parameters": [ + { + "name": "title", + "type": "string", + "description": "Title that is displayed under the extension icon in the toolbar." + }, + { + "name": "iconURL", + "type": "string", + "description": "An URL of the toolbar icon." + }, + { + "name": "pageURL", + "type": "string", + "description": "An URL of the page that represents this panel." + } + ], + "returns" : { + "$ref": "ExtensionPanel", + "description": "A panel that was created." + } + } + ] + }, + { + "namespace": "experimental.webInspector.resources", + "types": [ + { + "id": "Resource", + "type": "object", + "description": "Represents a resource (document, script, image etc). See HAR Specification for reference.", + "functions": [ + { + "name": "getContent", + "type": "function", + "description": "Returns resource content.", + "parameters": [ + { + "name": "callback", + "type": "function", + "description": "A function that is called upon request completion.", + "parameters": [ + { + "name": "content", + "type": "string", + "description": "Resource content (potentially encoded)." + }, + { + "name": "encoding", + "type": "string", + "description": "Empty if content is not encoded, encoding name otherwise. Currently, only base64 supported." + } + ] + } + ] + } + ] + } + ], + "functions": [ + { + "name": "getHAR", + "type": "function", + "description": "Returns HAR archive that contains all known resource objects.", + "parameters": [ + { + "name": "callback", + "type": "function", + "description": "A function that is called upon request completion.", + "parameters": [ + { + "name": "har", + "type": "object", + "description": "A HAR archieve. See HAR specification for details." + } + ] + } + ] + } + ], + "events": [ + { + "name": "onFinished", + "type": "function", + "description": "Fired when a resource request is finished and all resource data are available.", + "parameters": [ + { "name": "resource", "$ref": "Resource" } + ] + } + ] + }, + { + "namespace": "experimental.webInspector.audits", + "functions": [ + { + "name": "addCategory", + "type": "function", + "description": "Adds an audit category.", + "parameters": [ + { "name": "displayName", "type": "string", "description": "A display name for the category" }, + { "name": "resultCount", "type": "number", "description": "The expected number of audit results in the category." } + ], + "returns": { + "$ref": "AuditCategory" + } + } + ], + "types": [ + { + "id": "AuditCategory", + "type": "object", + "description": "A set of audit rules", + "events": [ + { + "name": "onAuditStarted", + "type": "function", + "description": "Fired when the audit is started, if the category is enabled -- the extension is expected to begin executing audit rules.", + "parameters": [ + { "name": "results", "$ref": "AuditResults" } + ] + } + ] + }, + { + "id": "FormattedValue", + "type": "object", + "description": "A value returned from one of the formatters (an URL, code snippet etc), to be passed to createResult or addChild" + }, + { + "id": "AuditResults", + "type": "object", + "description": "A collection of audit results for current run of the audit category", + "functions": [ + { + "name": "addResult", + "type": "function", + "parameters": [ + { + "name": "displayName", + "type": "string", + "description": "A concise, high-level description of audit rule result" + }, + { + "name": "description", + "type": "string", + "description": "A detailed description of what the displayName means" + }, + { + "name": "severity", + "$ref": "AuditResultSeverety" + }, + { + "name": "details", + "$ref": "AuditResultNode", + "optional": true, + "description": "A subtree that appears under added result that may provide additional details on the violations found" + } + ] + }, + { + "name": "createResult", + "type": "function", + "description": "Creates a result node that may be user as details parameters to addResult", + "parameters": [ + { + "name": "content ...", + "choices": [ + { "type": "string" }, + { "$ref": "FormattedValue" } + ], + "description": "Either string or formatted values returned by one of AuditResult formatters (url, snippet etc)" + } + ], + "returns": { + "$ref": "AuditResultNode" + } + }, + { + "name": "done", + "type": "function", + "description": "Signals the WebInspector Audits panel that the run of this category is over. Normally the run completes automatically when a number of added top-level results is equal to that declared when AuditCategory was created." + }, + { + "name": "url", + "type": "function", + "description": "Render passed value as an URL in the Audits panel", + "parameters": [ + { "name": "href", "type": "string", "description": "An URL that will appear as href value on resulting link" }, + { "name": "displayText", "type": "string", "description": "A text that will appear to user", "optional": true } + ], + "returns": { "$ref": "FormattedValue" } + }, + { + "name": "snippet", + "type": "function", + "description": "Render passed text as a code snippet in the Audits panel", + "parameters": [ + { "name": "text", "type": "string", "description": "Snippet text" } + ], + "returns": { "$ref": "FormattedValue" } + } + ], + "properties": { + "Severity": { + "$ref": "AuditResultSeverity", + "description": "A class that contains possible values for audit result severities." + }, + "text": { + "type": "string", + "description": "The contents of the node." + }, + "children": { + "optional": true, + "type": "array", + "items": { "$ref": "AuditResultNode" }, + "description": "Children of this node." + }, + "expanded": { + "optional": "true", + "type": "boolean", + "description": "Whether the node is expanded by default." + } + } + }, + { + "id": "AuditResultNode", + "type": "object", + "description": "A node in the audit result trees. Displays some content and optionally has children node", + "functions": [ + { + "name": "addChild", + "description": "Adds another child node to this node", + "parameters": [ + { + "name": "content ...", + "choices": [ + { "type": "string" }, + { "$ref": "FormattedValue" } + ], + "description": "Either string or formatted values returned by one of AuditResult formatters (url, snippet etc)" + } + ], + "returns": { + "$ref": "AuditResultNode" + } + } + ], + "properties": { + "expanded": { + "type": "boolean", + "description": "If set, the subtree will always be expanded" + } + } + }, + { + "id": "AuditResultSeverity", + "type": "object", + "properties": { + "Info": { + "type": "string" + }, + "Warning": { + "type": "string" + }, + "Severe": { + "type": "string" + } + } + } + ] + } +] + diff --git a/Source/WebCore/inspector/front-end/ExtensionPanel.js b/Source/WebCore/inspector/front-end/ExtensionPanel.js index fb98350..144d55d 100644 --- a/Source/WebCore/inspector/front-end/ExtensionPanel.js +++ b/Source/WebCore/inspector/front-end/ExtensionPanel.js @@ -95,7 +95,7 @@ WebInspector.ExtensionWatchSidebarPane.prototype = { setExpression: function(expression, title) { - InspectorBackend.evaluate(expression, "extension-watch", this._onEvaluate.bind(this, title)); + InspectorBackend.evaluate(expression, "extension-watch", false, this._onEvaluate.bind(this, title)); }, _onEvaluate: function(title, result) diff --git a/Source/WebCore/inspector/front-end/ExtensionServer.js b/Source/WebCore/inspector/front-end/ExtensionServer.js index 0924106..7d33b73 100644 --- a/Source/WebCore/inspector/front-end/ExtensionServer.js +++ b/Source/WebCore/inspector/front-end/ExtensionServer.js @@ -252,9 +252,12 @@ WebInspector.ExtensionServer.prototype = { WebInspector.log(message.message); }, - _onReload: function() + _onReload: function(message) { - InspectorBackend.reloadPage(); + if (typeof message.userAgent === "string") + InspectorBackend.setUserAgentOverride(message.userAgent); + + InspectorBackend.reloadPage(false); return this._status.OK(); }, @@ -269,10 +272,8 @@ WebInspector.ExtensionServer.prototype = { result.value = resultObject.description; this._dispatchCallback(message.requestId, port, result); } - var evalExpression = "JSON.stringify(eval('" + - "with (window.console._commandLineAPI) with (window) {' + unescape('" + escape(message.expression) + - "') + '}'));"; - InspectorBackend.evaluate(evalExpression, "none", callback.bind(this)); + var evalExpression = "JSON.stringify(eval(unescape('" + escape(message.expression) + "')));"; + InspectorBackend.evaluate(evalExpression, "none", true, callback.bind(this)); }, _onRevealAndSelect: function(message) diff --git a/Source/WebCore/inspector/front-end/FileSystemView.js b/Source/WebCore/inspector/front-end/FileSystemView.js deleted file mode 100644 index 56f21a4..0000000 --- a/Source/WebCore/inspector/front-end/FileSystemView.js +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.FileSystemDispatcher = function() -{ -} - -// Keep in sync with Type in AsyncFileSystem.h -WebInspector.FileSystemDispatcher.TEMPORARY = 0; -WebInspector.FileSystemDispatcher.PERSISTENT = 1; - -WebInspector.FileSystemDispatcher.prototype = { - getFileSystemPathsAsync: function(origin) - { - InspectorBackend.getFileSystemPathAsync(WebInspector.FileSystemDispatcher.PERSISTENT, origin); - InspectorBackend.getFileSystemPathAsync(WebInspector.FileSystemDispatcher.TEMPORARY, origin); - }, - - didGetFileSystemPath: function(root, type, origin) - { - WebInspector.panels.resources.updateFileSystemPath(root, type, origin); - }, - - didGetFileSystemError: function(type, origin) - { - WebInspector.panels.resources.updateFileSystemError(type, origin); - }, - - didGetFileSystemDisabled: function() - { - WebInspector.panels.resources.setFileSystemDisabled(); - } -} - -InspectorBackend.registerDomainDispatcher("FileSystem", new WebInspector.FileSystemDispatcher()); - -WebInspector.FileSystemView = function(treeElement, fileSystemOrigin) -{ - WebInspector.View.call(this); - - this.element.addStyleClass("resource-view"); - this._treeElement = treeElement; - this._origin = fileSystemOrigin; - this._tabbedPane = new WebInspector.TabbedPane(this.element); - - this._persistentFileSystemElement = document.createElement("div"); - this._persistentFileSystemElement.className = "resource-view-headers"; - this._tabbedPane.appendTab("persistent", WebInspector.UIString("Persistent File System"), this._persistentFileSystemElement, this._selectFileSystemTab.bind(this, true)); - - this._tempFileSystemElement = document.createElement("div"); - this._tempFileSystemElement.className = "resource-view-headers"; - this._tabbedPane.appendTab("temp", WebInspector.UIString("Temporary File System"), this._tempFileSystemElement, this.selectTemporaryFileSystemTab.bind(this, true)); - - this._temporaryRoot = ""; - this._persistentRoot = ""; - this._isFileSystemDisabled = false; - this._persistentRootError = false; - this._temporaryRootError = false; - this.fileSystemVisible = true; - this._selectFileSystemTab(); - this.refreshFileSystem(); -} - -WebInspector.FileSystemView.prototype = { - show: function(parentElement) - { - WebInspector.View.prototype.show.call(this, parentElement); - this._update(); - }, - - set fileSystemVisible(x) - { - if (x === this._fileSystemVisible) - return; - this._fileSystemVisible = x; - if (x) - this.element.addStyleClass("headers-visible"); - else - this.element.removeStyleClass("headers-visible"); - this._selectFileSystemTab(); - }, - - _update: function() - { - this._selectFileSystemTab(); - WebInspector.FileSystem.getFileSystemPathsAsync(this._origin); - }, - - updateFileSystemPath: function(root, type, origin) - { - if (origin == this._origin && type == WebInspector.FileSystem.PERSISTENT) { - this._persistentRoot = root; - this._persistentRootError = false; - } - - if (origin == this._origin && type == WebInspector.FileSystem.TEMPORARY) { - this._temporaryRoot = root; - this._temporaryRootErrorError = false; - } - - this.refreshFileSystem(); - }, - - updateFileSystemError: function(type, origin) - { - if (type == WebInspector.FileSystem.PERSISTENT) - this._persistentRootError = true; - - if (type == WebInspector.FileSystem.TEMPORARY) - this._temporaryRootError = true; - - this.refreshFileSystem(); - }, - - setFileSystemDisabled: function() - { - this._isFileSystemDisabled = true; - this.refreshFileSystem(); - }, - _selectFileSystemTab: function() - { - this._tabbedPane.selectTab("persistent"); - }, - - selectTemporaryFileSystemTab: function() - { - this._tabbedPane.selectTab("temp"); - }, - - _revealPersistentFolderInOS: function() - { - InspectorBackend.revealFolderInOS(this._persistentRoot); - }, - - _revealTemporaryFolderInOS: function() - { - InspectorBackend.revealFolderInOS(this._temporaryRoot); - }, - - _createTextAndButton: function(fileSystemElement, rootPathText, type, isError) - { - fileSystemElement.removeChildren(); - var rootPath = WebInspector.UIString("File System root path not available."); - if (this._isFileSystemDisabled) - rootPath = WebInspector.UIString("File System is disabled."); - else if (isError) - rootPath = WebInspector.UIString("Error in fetching root path for file system."); - else if (rootPathText) - rootPath = rootPathText; - - var rootTextNode = document.createTextNode("Root: " + rootPath.escapeHTML()); - var rootSystemElement = document.createElement("div"); - rootSystemElement.className = "header-value source-code"; - rootSystemElement.appendChild(rootTextNode); - fileSystemElement.appendChild(rootSystemElement); - - if (!isError && rootPathText) { - // Append Browse button iff root path is available and it is not an error. - var contentElement = document.createElement("div"); - contentElement.className = "panel-enabler-view-content"; - fileSystemElement.appendChild(contentElement); - var choicesForm = document.createElement("form"); - contentElement.appendChild(choicesForm); - var enableButton = document.createElement("button"); - enableButton.setAttribute("type", "button"); - enableButton.textContent = WebInspector.UIString("Reveal folder in OS"); - // FIXME: Bind this directly to InspectorBackend. - if (type == WebInspector.FileSystem.PERSISTENT) - enableButton.addEventListener("click", this._revealPersistentFolderInOS.bind(this), false); - if (type == WebInspector.FileSystem.TEMPORARY) - enableButton.addEventListener("click", this._revealTemporaryFolderInOS.bind(this), false); - choicesForm.appendChild(enableButton); - fileSystemElement.appendChild(contentElement); - } - }, - - refreshFileSystem: function() - { - this._createTextAndButton(this._persistentFileSystemElement, this._persistentRoot, WebInspector.FileSystem.PERSISTENT, this._persistentRootError); - this._createTextAndButton(this._tempFileSystemElement, this._temporaryRoot, WebInspector.FileSystem.TEMPORARY, this._temporaryRootError); - }, -} - -WebInspector.FileSystemView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/Source/WebCore/inspector/front-end/GoToLineDialog.js b/Source/WebCore/inspector/front-end/GoToLineDialog.js index c96344c..f246159 100644 --- a/Source/WebCore/inspector/front-end/GoToLineDialog.js +++ b/Source/WebCore/inspector/front-end/GoToLineDialog.js @@ -45,7 +45,7 @@ WebInspector.GoToLineDialog = function(view) this._input = dialogWindow.createChild("input"); this._input.setAttribute("type", "text"); this._input.setAttribute("size", 6); - var linesCount = view.sourceFrame.textModel.linesCount; + var linesCount = view.textModel.linesCount; if (linesCount) this._input.setAttribute("title", WebInspector.UIString("1 - %d", linesCount)); var blurHandler = this._onBlur.bind(this); @@ -120,7 +120,7 @@ WebInspector.GoToLineDialog.prototype = { var value = this._input.value; var lineNumber = parseInt(value, 10); if (!isNaN(lineNumber) && lineNumber > 0) { - lineNumber = Math.min(lineNumber, this._view.sourceFrame.textModel.linesCount); + lineNumber = Math.min(lineNumber, this._view.textModel.linesCount); this._view.highlightLine(lineNumber); } } diff --git a/Source/WebCore/inspector/front-end/HeapSnapshot.js b/Source/WebCore/inspector/front-end/HeapSnapshot.js new file mode 100644 index 0000000..ef450af --- /dev/null +++ b/Source/WebCore/inspector/front-end/HeapSnapshot.js @@ -0,0 +1,909 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.HeapSnapshotArraySlice = function(snapshot, arrayName, start, end) +{ + // Note: we don't reference snapshot contents directly to avoid + // holding references to big chunks of data. + this._snapshot = snapshot; + this._arrayName = arrayName; + this._start = start; + this.length = end - start; +} + +WebInspector.HeapSnapshotArraySlice.prototype = { + item: function(index) + { + return this._snapshot[this._arrayName][this._start + index]; + } +} + +WebInspector.HeapSnapshotEdge = function(snapshot, edges, edgeIndex) +{ + this._snapshot = snapshot; + this._edges = edges; + this.edgeIndex = edgeIndex || 0; +} + +WebInspector.HeapSnapshotEdge.prototype = { + clone: function() + { + return new WebInspector.HeapSnapshotEdge(this._snapshot, this._edges, this.edgeIndex); + }, + + get hasStringName() + { + if (!this.isShortcut) + return this._hasStringName; + return isNaN(parseInt(this._name, 10)); + }, + + get isElement() + { + return this._type() === this._snapshot._edgeElementType; + }, + + get isHidden() + { + return this._type() === this._snapshot._edgeHiddenType; + }, + + get isInternal() + { + return this._type() === this._snapshot._edgeInternalType; + }, + + get isShortcut() + { + return this._type() === this._snapshot._edgeShortcutType; + }, + + get name() + { + if (!this.isShortcut) + return this._name; + var numName = parseInt(this._name, 10); + return isNaN(numName) ? this._name : numName; + }, + + get node() + { + return new WebInspector.HeapSnapshotNode(this._snapshot, this.nodeIndex); + }, + + get nodeIndex() + { + return this._edges.item(this.edgeIndex + this._snapshot._edgeToNodeOffset); + }, + + get rawEdges() + { + return this._edges; + }, + + toString: function() + { + switch (this.type) { + case "context": return "->" + this.name; + case "element": return "[" + this.name + "]"; + case "property": + return this.name.indexOf(" ") === -1 ? "." + this.name : "[\"" + this.name + "\"]"; + case "shortcut": + var name = this.name; + if (typeof name === "string") + return this.name.indexOf(" ") === -1 ? "." + this.name : "[\"" + this.name + "\"]"; + else + return "[" + this.name + "]"; + case "internal": + case "hidden": + return "{" + this.name + "}"; + }; + return "?" + this.name + "?"; + }, + + get type() + { + return this._snapshot._edgeTypes[this._type()]; + }, + + get _hasStringName() + { + return !this.isElement && !this.isHidden; + }, + + get _name() + { + return this._hasStringName ? this._snapshot._strings[this._nameOrIndex] : this._nameOrIndex; + }, + + get _nameOrIndex() + { + return this._edges.item(this.edgeIndex + this._snapshot._edgeNameOffset); + }, + + _type: function() + { + return this._edges.item(this.edgeIndex + this._snapshot._edgeTypeOffset); + } +}; + +WebInspector.HeapSnapshotEdgeIterator = function(edge) +{ + this.edge = edge; +} + +WebInspector.HeapSnapshotEdgeIterator.prototype = { + first: function() + { + this.edge.edgeIndex = 0; + }, + + hasNext: function() + { + return this.edge.edgeIndex < this.edge._edges.length; + }, + + get index() + { + return this.edge.edgeIndex; + }, + + set index(newIndex) + { + this.edge.edgeIndex = newIndex; + }, + + get item() + { + return this.edge; + }, + + next: function() + { + this.edge.edgeIndex += this.edge._snapshot._edgeFieldsCount; + } +}; + +WebInspector.HeapSnapshotNode = function(snapshot, nodeIndex) +{ + this._snapshot = snapshot; + this._firstNodeIndex = nodeIndex; + this.nodeIndex = nodeIndex; +} + +WebInspector.HeapSnapshotNode.prototype = { + get className() + { + switch (this.type) { + case "hidden": + return WebInspector.UIString("(system)"); + case "object": + return this.name; + case "code": + return WebInspector.UIString("(compiled code)"); + default: + return "(" + this.type + ")"; + } + }, + + dominatorIndex: function() + { + return this._nodes[this.nodeIndex + this._snapshot._dominatorOffset]; + }, + + get edges() + { + return new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(this._snapshot, this.rawEdges)); + }, + + get edgesCount() + { + return this._nodes[this.nodeIndex + this._snapshot._edgesCountOffset]; + }, + + get id() + { + return this._nodes[this.nodeIndex + this._snapshot._nodeIdOffset]; + }, + + get instancesCount() + { + return this._nodes[this.nodeIndex + this._snapshot._nodeInstancesCountOffset]; + }, + + get isHidden() + { + return this._type() === this._snapshot._nodeHiddenType; + }, + + get isRoot() + { + return this.nodeIndex === this._snapshot._rootNodeIndex; + }, + + get name() + { + return this._snapshot._strings[this._name()]; + }, + + get rawEdges() + { + var firstEdgeIndex = this._firstEdgeIndex(); + return new WebInspector.HeapSnapshotArraySlice(this._snapshot, "_nodes", firstEdgeIndex, firstEdgeIndex + this.edgesCount * this._snapshot._edgeFieldsCount); + }, + + get retainedSize() + { + return this._nodes[this.nodeIndex + this._snapshot._nodeRetainedSizeOffset]; + }, + + get retainers() + { + return new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(this._snapshot, this._snapshot.retainers(this))); + }, + + get selfSize() + { + return this._nodes[this.nodeIndex + this._snapshot._nodeSelfSizeOffset]; + }, + + get type() + { + return this._snapshot._nodeTypes[this._type()]; + }, + + _name: function() + { + return this._nodes[this.nodeIndex + this._snapshot._nodeNameOffset]; + }, + + get _nodes() + { + return this._snapshot._nodes; + }, + + _firstEdgeIndex: function() + { + return this.nodeIndex + this._snapshot._firstEdgeOffset; + }, + + get _nextNodeIndex() + { + return this._firstEdgeIndex() + this.edgesCount * this._snapshot._edgeFieldsCount; + }, + + _type: function() + { + return this._nodes[this.nodeIndex + this._snapshot._nodeTypeOffset]; + } +}; + +WebInspector.HeapSnapshotNodeIterator = function(node) +{ + this.node = node; +} + +WebInspector.HeapSnapshotNodeIterator.prototype = { + first: function() + { + this.node.nodeIndex = this.node._firstNodeIndex; + }, + + hasNext: function() + { + return this.node.nodeIndex < this.node._nodes.length; + }, + + get index() + { + return this.node.nodeIndex; + }, + + set index(newIndex) + { + this.node.nodeIndex = newIndex; + }, + + get item() + { + return this.node; + }, + + next: function() + { + this.node.nodeIndex = this.node._nextNodeIndex; + } +} + +WebInspector.HeapSnapshot = function(profile) +{ + this._nodes = profile.nodes; + this._strings = profile.strings; + + this._init(); +} + +WebInspector.HeapSnapshot.prototype = { + _init: function() + { + this._metaNodeIndex = 0; + this._rootNodeIndex = 1; + var meta = this._nodes[this._metaNodeIndex]; + this._nodeTypeOffset = meta.fields.indexOf("type"); + this._nodeNameOffset = meta.fields.indexOf("name"); + this._nodeIdOffset = meta.fields.indexOf("id"); + this._nodeInstancesCountOffset = this._nodeIdOffset; + this._nodeSelfSizeOffset = meta.fields.indexOf("self_size"); + this._nodeRetainedSizeOffset = meta.fields.indexOf("retained_size"); + this._dominatorOffset = meta.fields.indexOf("dominator"); + this._edgesCountOffset = meta.fields.indexOf("children_count"); + this._firstEdgeOffset = meta.fields.indexOf("children"); + this._nodeTypes = meta.types[this._nodeTypeOffset]; + this._nodeHiddenType = this._nodeTypes.indexOf("hidden"); + var edgesMeta = meta.types[this._firstEdgeOffset]; + this._edgeFieldsCount = edgesMeta.fields.length; + this._edgeTypeOffset = edgesMeta.fields.indexOf("type"); + this._edgeNameOffset = edgesMeta.fields.indexOf("name_or_index"); + this._edgeToNodeOffset = edgesMeta.fields.indexOf("to_node"); + this._edgeTypes = edgesMeta.types[this._edgeTypeOffset]; + this._edgeElementType = this._edgeTypes.indexOf("element"); + this._edgeHiddenType = this._edgeTypes.indexOf("hidden"); + this._edgeInternalType = this._edgeTypes.indexOf("internal"); + this._edgeShortcutType = this._edgeTypes.indexOf("shortcut"); + }, + + dispose: function() + { + delete this._nodes; + delete this._strings; + if (this._idsMap) + delete this._idsMap; + if (this._retainers) { + delete this._retainers; + delete this._nodesToRetainers; + } + if (this._aggregates) { + delete this._aggregates; + this._aggregatesWithIndexes = false; + } + }, + + get allNodes() + { + return new WebInspector.HeapSnapshotNodeIterator(this.rootNode); + }, + + get nodesCount() + { + if (this._nodesCount) + return this._nodesCount; + + this._nodesCount = 0; + for (var iter = this.allNodes; iter.hasNext(); iter.next()) + ++this._nodesCount; + return this._nodesCount; + }, + + restore: function(profile) + { + this._nodes = profile.nodes; + this._strings = profile.strings; + }, + + get rootNode() + { + return new WebInspector.HeapSnapshotNode(this, this._rootNodeIndex); + }, + + get totalSize() + { + return this.rootNode.retainedSize; + }, + + get idsMap() + { + if (this._idsMap) + return this._idsMap; + + this._idsMap = []; + for (var iter = this.allNodes; iter.hasNext(); iter.next()) { + this._idsMap[iter.node.id] = true; + } + return this._idsMap; + }, + + retainers: function(node) + { + if (!this._retainers) + this._buildRetainers(); + + var retIndexFrom = this._nodesToRetainers[node.nodeIndex]; + var retIndexTo = this._nodesToRetainers[node._nextNodeIndex]; + return new WebInspector.HeapSnapshotArraySlice(this, "_retainers", retIndexFrom, retIndexTo); + }, + + aggregates: function(withNodeIndexes) + { + if (!this._aggregates) + this._buildAggregates(); + if (withNodeIndexes && !this._aggregatesWithIndexes) + this._buildAggregatesIndexes(); + return this._aggregates; + }, + + _buildRetainers: function() + { + this._nodesToRetainers = []; + for (var nodesIter = this.allNodes; nodesIter.hasNext(); nodesIter.next()) { + var node = nodesIter.node; + if (!(node.nodeIndex in this._nodesToRetainers)) + this._nodesToRetainers[node.nodeIndex] = 0; + for (var edgesIter = node.edges; edgesIter.hasNext(); edgesIter.next()) { + var edge = edgesIter.edge; + var nodeIndex = edge.nodeIndex; + if (!(nodeIndex in this._nodesToRetainers)) + this._nodesToRetainers[nodeIndex] = 0; + this._nodesToRetainers[nodeIndex] += this._edgeFieldsCount; + } + } + nodesIter = this.allNodes; + var node = nodesIter.node; + var prevIndex = this._nodesToRetainers[node.nodeIndex] = 0; + var prevRetsCount = this._nodesToRetainers[node.nodeIndex]; + nodesIter.next(); + for (; nodesIter.hasNext(); nodesIter.next()) { + node = nodesIter.node; + var savedRefsCount = this._nodesToRetainers[node.nodeIndex]; + this._nodesToRetainers[node.nodeIndex] = prevIndex + prevRetsCount; + prevIndex = this._nodesToRetainers[node.nodeIndex]; + prevRetsCount = savedRefsCount; + } + this._retainers = new Array(prevIndex + prevRetsCount); + this._nodesToRetainers[this._nodes.length] = this._retainers.length; + for (nodesIter = this.allNodes; nodesIter.hasNext(); nodesIter.next()) { + node = nodesIter.node; + var retsCount = this._nodesToRetainers[node._nextNodeIndex] - this._nodesToRetainers[node.nodeIndex]; + if (retsCount > 0) { + this._retainers[this._nodesToRetainers[node.nodeIndex]] = retsCount; + } + } + for (nodesIter = this.allNodes; nodesIter.hasNext(); nodesIter.next()) { + node = nodesIter.node; + for (var edgesIter = node.edges; edgesIter.hasNext(); edgesIter.next()) { + var edge = edgesIter.edge; + var nodeIndex = edge.nodeIndex; + var retIndex = this._nodesToRetainers[nodeIndex]; + this._retainers[retIndex] -= this._edgeFieldsCount; + var idx = retIndex + this._retainers[retIndex]; + this._retainers[idx + this._edgeTypeOffset] = edge._type(); + this._retainers[idx + this._edgeNameOffset] = edge._nameOrIndex; + this._retainers[idx + this._edgeToNodeOffset] = node.nodeIndex; + } + } + }, + + _buildAggregates: function() + { + this._aggregates = {}; + for (var iter = this.allNodes; iter.hasNext(); iter.next()) { + var node = iter.node; + var className = node.className; + var nameMatters = node.type === "object"; + if (node.selfSize === 0) + continue; + if (!(className in this._aggregates)) + this._aggregates[className] = { count: 0, self: 0, maxRet: 0, type: node.type, name: nameMatters ? node.name : null, idxs: [] }; + var clss = this._aggregates[className]; + ++clss.count; + clss.self += node.selfSize; + if (node.retainedSize > clss.maxRet) + clss.maxRet = node.retainedSize; + } + }, + + _buildAggregatesIndexes: function() + { + for (var iter = this.allNodes; iter.hasNext(); iter.next()) { + var node = iter.node; + var className = node.className; + var clss = this._aggregates[className]; + if (clss) + clss.idxs.push(node.nodeIndex); + } + + var nodeA = new WebInspector.HeapSnapshotNode(this); + var nodeB = new WebInspector.HeapSnapshotNode(this); + for (var clss in this._aggregates) + this._aggregates[clss].idxs.sort( + function(idxA, idxB) { + nodeA.nodeIndex = idxA; + nodeB.nodeIndex = idxB; + return nodeA.id < nodeB.id ? -1 : 1; + }); + + this._aggregatesWithIndexes = true; + } +}; + +WebInspector.HeapSnapshotFilteredOrderedIterator = function(snapshot, iterator, filter) +{ + this._snapshot = snapshot; + this._filter = filter; + this._iterator = iterator; + this._iterationOrder = null; + this._position = 0; + this._lastComparator = null; +} + +WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = { + _createIterationOrder: function() + { + this._iterationOrder = []; + var iterator = this._iterator; + if (!this._filter) { + for (iterator.first(); iterator.hasNext(); iterator.next()) + this._iterationOrder.push(iterator.index); + } else { + for (iterator.first(); iterator.hasNext(); iterator.next()) { + if (this._filter(iterator.item)) + this._iterationOrder.push(iterator.index); + } + } + }, + + first: function() + { + this._position = 0; + }, + + hasNext: function() + { + return this._position < this._iterationOrder.length; + }, + + get isEmpty() + { + if (this._iterationOrder) + return !this._iterationOrder.length; + var iterator = this._iterator; + if (!this._filter) { + iterator.first(); + return !iterator.hasNext(); + } + for (iterator.first(); iterator.hasNext(); iterator.next()) + if (this._filter(iterator.item)) return false; + return true; + }, + + get item() + { + this._iterator.index = this._iterationOrder[this._position]; + return this._iterator.item; + }, + + get lastComparator() + { + return this._lastComparator; + }, + + get length() + { + if (!this._iterationOrder) + this._createIterationOrder(); + return this._iterationOrder.length; + }, + + next: function() + { + ++this._position; + } +} + +WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator = function(fieldNames) +{ + return {fieldName1:fieldNames[0], ascending1:fieldNames[1], fieldName2:fieldNames[2], ascending2:fieldNames[3]}; +} + +WebInspector.HeapSnapshotEdgesProvider = function(snapshot, rawEdges, filter) +{ + WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot, new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(snapshot, rawEdges)), filter); +} + +WebInspector.HeapSnapshotEdgesProvider.prototype = { + sort: function(comparator) + { + if (this._lastComparator === comparator) + return false; + this._lastComparator = comparator; + var fieldName1 = comparator.fieldName1; + var fieldName2 = comparator.fieldName2; + var ascending1 = comparator.ascending1; + var ascending2 = comparator.ascending2; + + var edgeA = this._iterator.item.clone(); + var edgeB = edgeA.clone(); + var nodeA = new WebInspector.HeapSnapshotNode(this._snapshot); + var nodeB = new WebInspector.HeapSnapshotNode(this._snapshot); + + function sortByEdgeFieldName(ascending, indexA, indexB) + { + edgeA.edgeIndex = indexA; + edgeB.edgeIndex = indexB; + if (edgeB.name === "__proto__") return -1; + if (edgeA.name === "__proto__") return 1; + var result = + edgeA.hasStringName === edgeB.hasStringName ? + (edgeA.name < edgeB.name ? -1 : (edgeA.name > edgeB.name ? 1 : 0)) : + (edgeA.hasStringName ? -1 : 1); + return ascending ? result : -result; + } + + function sortByNodeField(fieldName, ascending, indexA, indexB) + { + edgeA.edgeIndex = indexA; + edgeB.edgeIndex = indexB; + nodeA.nodeIndex = edgeA.nodeIndex; + nodeB.nodeIndex = edgeB.nodeIndex; + var valueA = nodeA[fieldName]; + var valueB = nodeB[fieldName]; + var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0); + return ascending ? result : -result; + } + + if (!this._iterationOrder) + this._createIterationOrder(); + + function sortByEdgeAndNode(indexA, indexB) { + var result = sortByEdgeFieldName(ascending1, indexA, indexB); + if (result === 0) + result = sortByNodeField(fieldName2, ascending2, indexA, indexB); + return result; + } + + function sortByNodeAndEdge(indexA, indexB) { + var result = sortByNodeField(fieldName1, ascending1, indexA, indexB); + if (result === 0) + result = sortByEdgeFieldName(ascending2, indexA, indexB); + return result; + } + + function sortByNodeAndNode(indexA, indexB) { + var result = sortByNodeField(fieldName1, ascending1, indexA, indexB); + if (result === 0) + result = sortByNodeField(fieldName2, ascending2, indexA, indexB); + return result; + } + + if (fieldName1 === "!edgeName") + this._iterationOrder.sort(sortByEdgeAndNode); + else if (fieldName2 === "!edgeName") + this._iterationOrder.sort(sortByNodeAndEdge); + else + this._iterationOrder.sort(sortByNodeAndNode); + return true; + } +}; + +WebInspector.HeapSnapshotEdgesProvider.prototype.__proto__ = WebInspector.HeapSnapshotFilteredOrderedIterator.prototype; + +WebInspector.HeapSnapshotNodesProvider = function(snapshot, nodes, filter) +{ + WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot, nodes, filter); +} + +WebInspector.HeapSnapshotNodesProvider.prototype = { + sort: function(comparator) + { + if (this._lastComparator === comparator) + return false; + this._lastComparator = comparator; + var fieldName1 = comparator.fieldName1; + var fieldName2 = comparator.fieldName2; + var ascending1 = comparator.ascending1; + var ascending2 = comparator.ascending2; + + var nodeA = new WebInspector.HeapSnapshotNode(this._snapshot); + var nodeB = new WebInspector.HeapSnapshotNode(this._snapshot); + + function sortByNodeField(fieldName, ascending, indexA, indexB) + { + nodeA.nodeIndex = indexA; + nodeB.nodeIndex = indexB; + var valueA = nodeA[fieldName]; + var valueB = nodeB[fieldName]; + var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0); + return ascending ? result : -result; + } + + if (!this._iterationOrder) + this._createIterationOrder(); + + function sortByComparator(indexA, indexB) { + var result = sortByNodeField(fieldName1, ascending1, indexA, indexB); + if (result === 0) + result = sortByNodeField(fieldName2, ascending2, indexA, indexB); + return result; + } + + this._iterationOrder.sort(sortByComparator); + return true; + } +}; + +WebInspector.HeapSnapshotNodesProvider.prototype.__proto__ = WebInspector.HeapSnapshotFilteredOrderedIterator.prototype; + +WebInspector.HeapSnapshotPathFinder = function(snapshot, targetNodeIndex) +{ + this._snapshot = snapshot; + this._maxLength = 1; + this._lengthLimit = 15; + this._targetNodeIndex = targetNodeIndex; + this._currentPath = null; + this._skipHidden = !WebInspector.DetailedHeapshotView.prototype.showHiddenData; + this._rootChildren = this._fillRootChildren(); +} + +WebInspector.HeapSnapshotPathFinder.prototype = { + findNext: function() + { + for (var i = 0; i < 100000; ++i) { + if (!this._buildNextPath()) { + if (++this._maxLength >= this._lengthLimit) + return null; + this._currentPath = null; + if (!this._buildNextPath()) + return null; + } + if (this._isPathFound()) + return {path:this._pathToString(this._currentPath), len:this._currentPath.length}; + } + + return false; + }, + + _fillRootChildren: function() + { + var result = []; + for (var iter = this._snapshot.rootNode.edges; iter.hasNext(); iter.next()) + result[iter.edge.nodeIndex] = true; + return result; + }, + + _appendToCurrentPath: function(iter) + { + this._currentPath._cache[this._lastEdge.nodeIndex] = true; + this._currentPath.push(iter); + }, + + _removeLastFromCurrentPath: function() + { + this._currentPath.pop(); + delete this._currentPath._cache[this._lastEdge.nodeIndex]; + }, + + _hasInPath: function(nodeIndex) + { + return this._targetNodeIndex === nodeIndex + || !!this._currentPath._cache[nodeIndex]; + }, + + _isPathFound: function() + { + return this._currentPath.length === this._maxLength + && this._lastEdge.nodeIndex in this._rootChildren; + }, + + get _lastEdgeIter() + { + return this._currentPath[this._currentPath.length - 1]; + }, + + get _lastEdge() + { + return this._lastEdgeIter.edge; + }, + + _skipEdge: function(edge) + { + return (this._skipHidden && (edge.isHidden || edge.node.isHidden)) + || this._hasInPath(edge.nodeIndex); + }, + + _nextEdgeIter: function() + { + var iter = this._lastEdgeIter; + while (this._skipEdge(iter.edge) && iter.hasNext()) + iter.next(); + return iter; + }, + + _buildNextPath: function() + { + if (this._currentPath !== null) { + var iter = this._lastEdgeIter; + while (true) { + iter.next(); + if (iter.hasNext()) + return true; + while (true) { + if (this._currentPath.length > 1) { + this._removeLastFromCurrentPath(); + iter = this._lastEdgeIter; + iter.next(); + iter = this._nextEdgeIter(); + if (iter.hasNext()) { + while (this._currentPath.length < this._maxLength) { + iter = this._nextEdgeIter(); + if (iter.hasNext()) + this._appendToCurrentPath(iter.edge.node.retainers); + else + return true; + } + return true; + } + } else + return false; + } + } + } else { + var node = new WebInspector.HeapSnapshotNode(this._snapshot, this._targetNodeIndex); + this._currentPath = [node.retainers]; + this._currentPath._cache = {}; + while (this._currentPath.length < this._maxLength) { + var iter = this._nextEdgeIter(); + if (iter.hasNext()) + this._appendToCurrentPath(iter.edge.node.retainers); + else + break; + } + return true; + } + }, + + _nodeToString: function(node) + { + if (node.id === 1) + return node.name; + else + return node.name + "@" + node.id; + }, + + _pathToString: function(path) + { + if (!path) + return ""; + var sPath = []; + for (var j = 0; j < path.length; ++j) + sPath.push(path[j].edge.toString()); + sPath.push(this._nodeToString(path[path.length - 1].edge.node)); + sPath.reverse(); + return sPath.join(""); + } +}; diff --git a/Source/WebCore/inspector/front-end/HeapSnapshotView.js b/Source/WebCore/inspector/front-end/HeapSnapshotView.js index f349361..44b95c3 100644 --- a/Source/WebCore/inspector/front-end/HeapSnapshotView.js +++ b/Source/WebCore/inspector/front-end/HeapSnapshotView.js @@ -27,154 +27,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.HeapSnapshotEdgesIterator = function(snapshot, edges) -{ - this._snapshot = snapshot; - this._edges = edges; - this._edgeIndex = 0; -} - -WebInspector.HeapSnapshotEdgesIterator.prototype = { - get done() - { - return this._edgeIndex >= this._edges.length; - }, - - get isElement() - { - return this._getType() === this._snapshot._edgeElementType; - }, - - get isHidden() - { - return this._getType() === this._snapshot._edgeHiddenType; - }, - - get name() - { - return this.isElement || this.isHidden ? this._getNameOrIndex() : this._snapshot._strings[this._getNameOrIndex()]; - }, - - next: function() - { - this._edgeIndex += this._snapshot._edgeFieldsCount; - }, - - get node() - { - return new WebInspector.HeapSnapshotNodeWrapper(this._snapshot, this.nodeIndex); - }, - - get nodeIndex() - { - return this._edges[this._edgeIndex + this._snapshot._edgeToNodeOffset]; - }, - - _getNameOrIndex: function() - { - return this._edges[this._edgeIndex + this._snapshot._edgeNameOffset]; - }, - - _getType: function() - { - return this._edges[this._edgeIndex + this._snapshot._edgeTypeOffset]; - } -}; - -WebInspector.HeapSnapshotNodeWrapper = function(snapshot, nodeIndex) -{ - this._snapshot = snapshot; - this._nodes = snapshot._nodes; - this._nodeIndex = nodeIndex; -} - -WebInspector.HeapSnapshotNodeWrapper.prototype = { - get edges() - { - return new WebInspector.HeapSnapshotEdgesIterator(this._snapshot, this._getEdges()); - }, - - get edgesCount() - { - return this._nodes[this._nodeIndex + this._snapshot._edgesCountOffset]; - }, - - get instancesCount() - { - return this._nodes[this._nodeIndex + this._snapshot._nodeInstancesCountOffset]; - }, - - get isHidden() - { - return this._getType() === this._snapshot._nodeHiddenType; - }, - - get name() - { - return this._snapshot._strings[this._getName()]; - }, - - get selfSize() - { - return this._nodes[this._nodeIndex + this._snapshot._nodeSelfSizeOffset]; - }, - - _getName: function() - { - return this._nodes[this._nodeIndex + this._snapshot._nodeNameOffset]; - }, - - _getEdges: function() - { - var firstEdgeIndex = this._nodeIndex + this._snapshot._firstEdgeOffset; - return this._nodes.slice(firstEdgeIndex, firstEdgeIndex + this.edgesCount * this._snapshot._edgeFieldsCount); - }, - - _getType: function() - { - return this._nodes[this._nodeIndex + this._snapshot._nodeTypeOffset]; - } -}; - -WebInspector.HeapSnapshot = function(profile) -{ - this._profile = profile; - this._nodes = profile.nodes; - this._strings = profile.strings; - - this._init(); -} - -WebInspector.HeapSnapshot.prototype = { - _init: function() - { - this._metaNodeIndex = 0; - this._rootNodeIndex = 1; - var meta = this._nodes[this._metaNodeIndex]; - this._nodeTypeOffset = meta.fields.indexOf("type"); - this._nodeNameOffset = meta.fields.indexOf("name"); - this._nodeIdOffset = meta.fields.indexOf("id"); - this._nodeInstancesCountOffset = this._nodeIdOffset; - this._nodeSelfSizeOffset = meta.fields.indexOf("self_size"); - this._edgesCountOffset = meta.fields.indexOf("children_count"); - this._firstEdgeOffset = meta.fields.indexOf("children"); - this._nodeTypes = meta.types[this._nodeTypeOffset]; - this._nodeHiddenType = this._nodeTypes.indexOf("hidden"); - var edgesMeta = meta.types[this._firstEdgeOffset]; - this._edgeFieldsCount = edgesMeta.fields.length; - this._edgeTypeOffset = edgesMeta.fields.indexOf("type"); - this._edgeNameOffset = edgesMeta.fields.indexOf("name_or_index"); - this._edgeToNodeOffset = edgesMeta.fields.indexOf("to_node"); - this._edgeTypes = edgesMeta.types[this._edgeTypeOffset]; - this._edgeElementType = this._edgeTypes.indexOf("element"); - this._edgeHiddenType = this._edgeTypes.indexOf("hidden"); - }, - - get rootEdges() - { - return (new WebInspector.HeapSnapshotNodeWrapper(this, this._rootNodeIndex)).edges; - } -}; WebInspector.HeapSnapshotView = function(parent, profile) { @@ -246,7 +98,7 @@ WebInspector.HeapSnapshotView = function(parent, profile) function profileCallback(profile) { - var list = this._getProfiles(); + var list = this._profiles(); var profileIndex; for (var i = 0; i < list.length; ++i) if (list[i].uid === profile.uid) { @@ -440,7 +292,7 @@ WebInspector.HeapSnapshotView.prototype = { _changeBase: function() { - if (this.baseSnapshot.uid === this._getProfiles()[this.baseSelectElement.selectedIndex].uid) + if (this.baseSnapshot.uid === this._profiles()[this.baseSelectElement.selectedIndex].uid) return; this._resetDataGridList(resetCompleted.bind(this)); @@ -468,7 +320,7 @@ WebInspector.HeapSnapshotView.prototype = { return this._snapshotDataGridList; }, - _getProfiles: function() + _profiles: function() { return WebInspector.panels.profiles.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId); }, @@ -530,17 +382,20 @@ WebInspector.HeapSnapshotView.prototype = { { var snapshot = new WebInspector.HeapSnapshot(loadedSnapshot); var result = {lowlevels: {}, entries: {}, children: {}}; - for (var rootEdges = snapshot.rootEdges; !rootEdges.done; rootEdges.next()) { - var node = rootEdges.node; + var rootEdgesIter = snapshot.rootNode.edges; + for (var iter = rootEdgesIter; iter.hasNext(); iter.next()) { + var node = iter.edge.node; if (node.isHidden) result.lowlevels[node.name] = {count: node.instancesCount, size: node.selfSize, type: node.name}; else if (node.instancesCount) result.entries[node.name] = {constructorName: node.name, count: node.instancesCount, size: node.selfSize}; else { var entry = {constructorName: node.name}; - for (var edges = node.edges; !edges.done; edges.next()) - entry[edges.nodeIndex] = {constructorName: edges.node.name, count: edges.name}; - result.children[rootEdges.nodeIndex] = entry; + for (var innerIter = node.edges; innerIter.hasNext(); innerIter.next()) { + var edge = innerIter.edge; + entry[edge.nodeIndex] = {constructorName: edge.node.name, count: edge.name}; + } + result.children[rootEdgesIter.edge.nodeIndex] = entry; } } return result; @@ -581,7 +436,7 @@ WebInspector.HeapSnapshotView.prototype = { _resetDataGridList: function(callback) { - this._loadProfile(this._getProfiles()[this.baseSelectElement.selectedIndex], profileLoaded.bind(this)); + this._loadProfile(this._profiles()[this.baseSelectElement.selectedIndex], profileLoaded.bind(this)); function profileLoaded(profile) { @@ -601,10 +456,10 @@ WebInspector.HeapSnapshotView.prototype = { var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; var sortProperty = { cons: ["constructorName", null], - count: ["count", null], - size: ["size", "count"], - countDelta: this.showCountDeltaAsPercent ? ["countDeltaPercent", null] : ["countDelta", null], - sizeDelta: this.showSizeDeltaAsPercent ? ["sizeDeltaPercent", "countDeltaPercent"] : ["sizeDelta", "sizeDeltaPercent"] + count: ["count", "constructorName"], + size: ["size", "constructorName"], + countDelta: [this.showCountDeltaAsPercent ? "countDeltaPercent" : "countDelta", "constructorName"], + sizeDelta: [this.showSizeDeltaAsPercent ? "sizeDeltaPercent" : "sizeDelta", "constructorName"] }[sortColumnIdentifier]; this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty[0], sortProperty[1], sortAscending)); @@ -614,7 +469,7 @@ WebInspector.HeapSnapshotView.prototype = { _updateBaseOptions: function() { - var list = this._getProfiles(); + var list = this._profiles(); // We're assuming that snapshots can only be added. if (this.baseSelectElement.length === list.length) return; @@ -1046,10 +901,17 @@ WebInspector.HeapSnapshotDataGridList.propertyComparator = function(property, pr if (!comparator) { comparator = function(lhs, rhs) { var l = lhs[property], r = rhs[property]; - if ((l === null || r === null) && property2 !== null) - l = lhs[property2], r = rhs[property2]; - var result = l < r ? -1 : (l > r ? 1 : 0); - return isAscending ? result : -result; + var result = 0; + if (l !== null && r !== null) { + result = l < r ? -1 : (l > r ? 1 : 0); + } + if (result !== 0 || property2 === null) { + return isAscending ? result : -result; + } else { + l = lhs[property2]; + r = rhs[property2]; + return l < r ? -1 : (l > r ? 1 : 0); + } }; this.propertyComparators[(isAscending ? 1 : 0)][propertyHash] = comparator; } @@ -1148,7 +1010,7 @@ WebInspector.HeapSnapshotProfileType.prototype = { buttonClicked: function() { - InspectorBackend.takeHeapSnapshot(); + InspectorBackend.takeHeapSnapshot(false); }, get welcomeMessage() diff --git a/Source/WebCore/inspector/front-end/NetworkManager.js b/Source/WebCore/inspector/front-end/NetworkManager.js index ed4309e..da043fe 100644 --- a/Source/WebCore/inspector/front-end/NetworkManager.js +++ b/Source/WebCore/inspector/front-end/NetworkManager.js @@ -31,86 +31,114 @@ WebInspector.NetworkManager = function(resourceTreeModel) { WebInspector.Object.call(this); - - this._inflightResources = {}; this._resourceTreeModel = resourceTreeModel; - this._lastIdentifierForCachedResource = 0; - InspectorBackend.registerDomainDispatcher("Network", this); + this._dispatcher = new WebInspector.NetworkDispatcher(resourceTreeModel, this); + InspectorBackend.cachedResources(this._processCachedResources.bind(this)); } -WebInspector.NetworkManager.requestContent = function(resource, base64Encode, callback) -{ - InspectorBackend.resourceContent(resource.loader.frameId, resource.url, base64Encode, callback); -} - -WebInspector.NetworkManager.updateResourceWithRequest = function(resource, request) -{ - resource.requestMethod = request.httpMethod; - resource.requestHeaders = request.httpHeaderFields; - resource.requestFormData = request.requestFormData; +WebInspector.NetworkManager.EventTypes = { + ResourceStarted: "ResourceStarted", + ResourceUpdated: "ResourceUpdated", + ResourceFinished: "ResourceFinished", + MainResourceCommitLoad: "MainResourceCommitLoad" } -WebInspector.NetworkManager.updateResourceWithResponse = function(resource, response) -{ - if (resource.isNull) - return; +WebInspector.NetworkManager.prototype = { + reset: function() + { + WebInspector.panels.network.clear(); + this._resourceTreeModel.reset(); + InspectorBackend.cachedResources(this._processCachedResources.bind(this)); + }, - resource.mimeType = response.mimeType; - resource.expectedContentLength = response.expectedContentLength; - resource.textEncodingName = response.textEncodingName; - resource.suggestedFilename = response.suggestedFilename; - resource.statusCode = response.httpStatusCode; - resource.statusText = response.httpStatusText; + requestContent: function(resource, base64Encode, callback) + { + function callbackWrapper(success, content) + { + callback(success ? content : null); + } + InspectorBackend.resourceContent(resource.loader.frameId, resource.url, base64Encode, callbackWrapper); + }, - resource.responseHeaders = response.httpHeaderFields; - resource.connectionReused = response.connectionReused; - resource.connectionID = response.connectionID; + _processCachedResources: function(mainFramePayload) + { + var mainResource = this._dispatcher._addFramesRecursively(mainFramePayload); + WebInspector.mainResource = mainResource; + mainResource.isMainResource = true; + }, - if (response.wasCached) - resource.cached = true; - else - resource.timing = response.timing; - - if (response.loadInfo) { - if (response.loadInfo.httpStatusCode) - resource.statusCode = response.loadInfo.httpStatusCode; - if (response.loadInfo.httpStatusText) - resource.statusText = response.loadInfo.httpStatusText; - resource.requestHeaders = response.loadInfo.requestHeaders; - resource.responseHeaders = response.loadInfo.responseHeaders; + inflightResourceForURL: function(url) + { + return this._dispatcher._inflightResourcesByURL[url]; } } -WebInspector.NetworkManager.updateResourceWithCachedResource = function(resource, cachedResource) +WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.NetworkDispatcher = function(resourceTreeModel, manager) { - resource.type = WebInspector.Resource.Type[cachedResource.type]; - resource.resourceSize = cachedResource.encodedSize; - WebInspector.NetworkManager.updateResourceWithResponse(resource, cachedResource.response); + this._manager = manager; + this._inflightResourcesById = {}; + this._inflightResourcesByURL = {}; + this._resourceTreeModel = resourceTreeModel; + this._lastIdentifierForCachedResource = 0; + InspectorBackend.registerDomainDispatcher("Network", this); } -WebInspector.NetworkManager.EventTypes = { - ResourceStarted: "ResourceStarted", - ResourceUpdated: "ResourceUpdated", - ResourceFinished: "ResourceFinished", - MainResourceCommitLoad: "MainResourceCommitLoad" -} +WebInspector.NetworkDispatcher.prototype = { + _updateResourceWithRequest: function(resource, request) + { + resource.requestMethod = request.httpMethod; + resource.requestHeaders = request.httpHeaderFields; + resource.requestFormData = request.requestFormData; + }, -WebInspector.NetworkManager.prototype = { - reset: function() + _updateResourceWithResponse: function(resource, response) { - WebInspector.panels.network.clear(); - WebInspector.panels.resources.clear(); - this._resourceTreeModel.reloadCachedResources(); + if (resource.isNull) + return; + + resource.mimeType = response.mimeType; + resource.expectedContentLength = response.expectedContentLength; + resource.textEncodingName = response.textEncodingName; + resource.suggestedFilename = response.suggestedFilename; + resource.statusCode = response.httpStatusCode; + resource.statusText = response.httpStatusText; + + resource.responseHeaders = response.httpHeaderFields; + resource.connectionReused = response.connectionReused; + resource.connectionID = response.connectionID; + + if (response.wasCached) + resource.cached = true; + else + resource.timing = response.timing; + + if (response.loadInfo) { + if (response.loadInfo.httpStatusCode) + resource.statusCode = response.loadInfo.httpStatusCode; + if (response.loadInfo.httpStatusText) + resource.statusText = response.loadInfo.httpStatusText; + resource.requestHeaders = response.loadInfo.requestHeaders; + resource.responseHeaders = response.loadInfo.responseHeaders; + } + }, + + _updateResourceWithCachedResource: function(resource, cachedResource) + { + resource.type = WebInspector.Resource.Type[cachedResource.type]; + resource.resourceSize = cachedResource.encodedSize; + this._updateResourceWithResponse(resource, cachedResource.response); }, identifierForInitialRequest: function(identifier, url, loader, callStack) { - this._startResource(this._resourceTreeModel.createResource(identifier, url, loader, callStack)); + this._startResource(this._createResource(identifier, url, loader, callStack)); }, willSendRequest: function(identifier, time, request, redirectResponse) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -122,7 +150,7 @@ WebInspector.NetworkManager.prototype = { resource = this._appendRedirect(resource.identifier, time, request.url); } - WebInspector.NetworkManager.updateResourceWithRequest(resource, request); + this._updateResourceWithRequest(resource, request); resource.startTime = time; if (isRedirect) @@ -133,7 +161,7 @@ WebInspector.NetworkManager.prototype = { markResourceAsCached: function(identifier) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -143,14 +171,14 @@ WebInspector.NetworkManager.prototype = { didReceiveResponse: function(identifier, time, resourceType, response) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; resource.responseReceivedTime = time; resource.type = WebInspector.Resource.Type[resourceType]; - WebInspector.NetworkManager.updateResourceWithResponse(resource, response); + this._updateResourceWithResponse(resource, response); this._updateResource(resource); this._resourceTreeModel.addResourceToFrame(resource.loader.frameId, resource); @@ -158,7 +186,7 @@ WebInspector.NetworkManager.prototype = { didReceiveContentLength: function(identifier, time, lengthReceived) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -170,7 +198,7 @@ WebInspector.NetworkManager.prototype = { didFinishLoading: function(identifier, finishTime) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -179,7 +207,7 @@ WebInspector.NetworkManager.prototype = { didFailLoading: function(identifier, time, localizedDescription) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -190,8 +218,8 @@ WebInspector.NetworkManager.prototype = { didLoadResourceFromMemoryCache: function(time, cachedResource) { - var resource = this._resourceTreeModel.createResource("cached:" + ++this._lastIdentifierForCachedResource, cachedResource.url, cachedResource.loader); - WebInspector.NetworkManager.updateResourceWithCachedResource(resource, cachedResource); + var resource = this._createResource("cached:" + ++this._lastIdentifierForCachedResource, cachedResource.url, cachedResource.loader); + this._updateResourceWithCachedResource(resource, cachedResource); resource.cached = true; resource.requestMethod = "GET"; this._startResource(resource); @@ -224,21 +252,21 @@ WebInspector.NetworkManager.prototype = { if (mainResource) { WebInspector.mainResource = mainResource; mainResource.isMainResource = true; - this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.MainResourceCommitLoad, mainResource); + this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.MainResourceCommitLoad, mainResource); } } }, didCreateWebSocket: function(identifier, requestURL) { - var resource = this._resourceTreeModel.createResource(identifier, requestURL); + var resource = this._createResource(identifier, requestURL); resource.type = WebInspector.Resource.Type.WebSocket; this._startResource(resource); }, willSendWebSocketHandshakeRequest: function(identifier, time, request) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -252,7 +280,7 @@ WebInspector.NetworkManager.prototype = { didReceiveWebSocketHandshakeResponse: function(identifier, time, response) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; @@ -267,7 +295,7 @@ WebInspector.NetworkManager.prototype = { didCloseWebSocket: function(identifier, time) { - var resource = this._inflightResources[identifier]; + var resource = this._inflightResourcesById[identifier]; if (!resource) return; this._finishResource(resource, time); @@ -275,40 +303,76 @@ WebInspector.NetworkManager.prototype = { _appendRedirect: function(identifier, time, redirectURL) { - var originalResource = this._inflightResources[identifier]; + var originalResource = this._inflightResourcesById[identifier]; var previousRedirects = originalResource.redirects || []; originalResource.identifier = "redirected:" + identifier + "." + previousRedirects.length; delete originalResource.redirects; this._finishResource(originalResource, time); - // We bound resource early, but it happened to be a redirect and won't make it through to - // the resource tree -- so unbind it. - // FIXME: we should bind upon adding to the tree only (encapsulated into ResourceTreeModel), - // Script debugger should do explicit late binding on its own. - this._resourceTreeModel.unbindResourceURL(originalResource); - - var newResource = this._resourceTreeModel.createResource(identifier, redirectURL, originalResource.loader, originalResource.stackTrace); + var newResource = this._createResource(identifier, redirectURL, originalResource.loader, originalResource.stackTrace); newResource.redirects = previousRedirects.concat(originalResource); return newResource; }, _startResource: function(resource) { - this._inflightResources[resource.identifier] = resource; - this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource); + this._inflightResourcesById[resource.identifier] = resource; + this._inflightResourcesByURL[resource.url] = resource; + this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource); }, _updateResource: function(resource) { - this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource); + this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource); }, _finishResource: function(resource, finishTime) { resource.endTime = finishTime; resource.finished = true; - this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource); - delete this._inflightResources[resource.identifier]; + this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource); + delete this._inflightResourcesById[resource.identifier]; + delete this._inflightResourcesByURL[resource.url]; + }, + + _addFramesRecursively: function(framePayload) + { + var frameResource = this._createResource(null, framePayload.resource.url, framePayload.resource.loader); + this._updateResourceWithRequest(frameResource, framePayload.resource.request); + this._updateResourceWithResponse(frameResource, framePayload.resource.response); + frameResource.type = WebInspector.Resource.Type["Document"]; + frameResource.finished = true; + + this._resourceTreeModel.addOrUpdateFrame(framePayload); + this._resourceTreeModel.addResourceToFrame(framePayload.id, frameResource); + + for (var i = 0; framePayload.children && i < framePayload.children.length; ++i) + this._addFramesRecursively(framePayload.children[i]); + + if (!framePayload.subresources) + return; + + for (var i = 0; i < framePayload.subresources.length; ++i) { + var cachedResource = framePayload.subresources[i]; + var resource = this._createResource(null, cachedResource.url, cachedResource.loader); + this._updateResourceWithCachedResource(resource, cachedResource); + resource.finished = true; + this._resourceTreeModel.addResourceToFrame(framePayload.id, resource); + } + return frameResource; + }, + + _dispatchEventToListeners: function(eventType, resource) + { + this._manager.dispatchEventToListeners(eventType, resource); + }, + + _createResource: function(identifier, url, loader, stackTrace) + { + var resource = new WebInspector.Resource(identifier, url); + resource.loader = loader; + if (loader) + resource.documentURL = loader.url; + resource.stackTrace = stackTrace; + return resource; } } - -WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/Source/WebCore/inspector/front-end/NetworkPanel.js b/Source/WebCore/inspector/front-end/NetworkPanel.js index 943ee7f..085f468 100644 --- a/Source/WebCore/inspector/front-end/NetworkPanel.js +++ b/Source/WebCore/inspector/front-end/NetworkPanel.js @@ -103,7 +103,7 @@ WebInspector.NetworkPanel.prototype = { elementsToRestoreScrollPositionsFor: function() { - return [this.containerElement]; + return [this.containerElement, this._dataGrid.scrollContainer]; }, resize: function() @@ -118,8 +118,6 @@ WebInspector.NetworkPanel.prototype = { if (!this._viewingResourceMode) return; WebInspector.Panel.prototype.updateSidebarWidth.call(this, width); - if (this._summaryBarElement.parentElement === this.element) - this._summaryBarElement.style.width = width + "px"; }, updateMainViewWidth: function(width) @@ -147,7 +145,6 @@ WebInspector.NetworkPanel.prototype = { delete this._summaryBarRowNode; } this._summaryBarElement.addStyleClass("network-summary-bar-bottom"); - this._summaryBarElement.style.setProperty("width", this.sidebarElement.offsetWidth + "px"); this.element.appendChild(this._summaryBarElement); this._dataGrid.element.style.bottom = "20px"; return; @@ -157,11 +154,11 @@ WebInspector.NetworkPanel.prototype = { // Glue status to table. this._summaryBarRowNode = new WebInspector.NetworkTotalGridNode(this._summaryBarElement); this._summaryBarElement.removeStyleClass("network-summary-bar-bottom"); - this._summaryBarElement.style.removeProperty("width"); this._dataGrid.appendChild(this._summaryBarRowNode); this._dataGrid.element.style.bottom = 0; this._sortItems(); } + this._updateOffscreenRows(); }, _resetSummaryBar: function() @@ -218,6 +215,7 @@ WebInspector.NetworkPanel.prototype = { this.containerElement.appendChild(this._dataGrid.element); this._dataGrid.addEventListener("sorting changed", this._sortItems, this); this._dataGrid.addEventListener("width changed", this._updateDividersIfNeeded, this); + this._dataGrid.scrollContainer.addEventListener("scroll", this._updateOffscreenRows.bind(this)); this._patchTimelineHeader(); }, @@ -316,6 +314,7 @@ WebInspector.NetworkPanel.prototype = { this._dataGrid.sortNodes(sortingFunction, this._dataGrid.sortOrder === "descending"); this._timelineSortSelector.selectedIndex = 0; + this._updateOffscreenRows(); }, _sortByTimeline: function() @@ -334,6 +333,7 @@ WebInspector.NetworkPanel.prototype = { else this._timelineGrid.showEventDividers(); this._dataGrid.markColumnAsSortedBy("timeline", "ascending"); + this._updateOffscreenRows(); }, _createFilterStatusBarItems: function() @@ -492,6 +492,7 @@ WebInspector.NetworkPanel.prototype = { target.addStyleClass("selected"); this._showCategory(target.category); } + this._updateOffscreenRows(); }, _scheduleRefresh: function() @@ -933,7 +934,6 @@ WebInspector.NetworkPanel.prototype = { this._viewsContainerElement.addStyleClass("hidden"); this.sidebarElement.style.right = 0; this.sidebarElement.style.removeProperty("width"); - this._summaryBarElement.style.removeProperty("width"); if (this._dataGrid.selectedNode) this._dataGrid.selectedNode.selected = false; } @@ -1023,13 +1023,55 @@ WebInspector.NetworkPanel.prototype = { var harArchive = { log: (new WebInspector.HARLog()).build() } - offerFileForDownload(JSON.stringify(harArchive)); + InspectorFrontendHost.copyText(JSON.stringify(harArchive)); }, _exportResource: function(resource) { var har = (new WebInspector.HAREntry(resource)).build(); - offerFileForDownload(JSON.stringify(har)); + InspectorFrontendHost.copyText(JSON.stringify(har)); + }, + + _updateOffscreenRows: function(e) + { + var dataTableBody = this._dataGrid.dataTableBody; + var rows = dataTableBody.children; + var recordsCount = rows.length; + if (recordsCount < 2) + return; // Filler row only. + + var visibleTop = this._dataGrid.scrollContainer.scrollTop; + var visibleBottom = visibleTop + this._dataGrid.scrollContainer.offsetHeight; + + var rowHeight = 0; + + // Filler is at recordsCount - 1. + var unfilteredRowIndex = 0; + for (var i = 0; i < recordsCount - 1; ++i) { + var row = rows[i]; + // Don't touch summaty - quit instead. + if (this._summaryBarRowNode && row === this._summaryBarRowNode.element) + break; + + var dataGridNode = this._dataGrid.dataGridNodeFromNode(row); + if (dataGridNode.isFilteredOut()) { + row.removeStyleClass("offscreen"); + continue; + } + + if (!rowHeight) + rowHeight = row.offsetHeight; + + var rowIsVisible = unfilteredRowIndex * rowHeight < visibleBottom && (unfilteredRowIndex + 1) * rowHeight > visibleTop; + if (rowIsVisible !== row.rowIsVisible) { + if (rowIsVisible) + row.removeStyleClass("offscreen"); + else + row.addStyleClass("offscreen"); + row.rowIsVisible = rowIsVisible; + } + unfilteredRowIndex++; + } } } @@ -1335,6 +1377,14 @@ WebInspector.NetworkDataGridNode.prototype = { this._timeCell = this._createDivInTD("time"); this._createTimelineCell(); this._nameCell.addEventListener("click", this.select.bind(this), false); + this._nameCell.addEventListener("dblclick", this._openInNewTab.bind(this), false); + }, + + isFilteredOut: function() + { + if (!this._panel._hiddenCategories.all) + return false; + return this._resource.category.name in this._panel._hiddenCategories; }, select: function() @@ -1343,15 +1393,16 @@ WebInspector.NetworkDataGridNode.prototype = { WebInspector.DataGridNode.prototype.select.apply(this, arguments); }, + _openInNewTab: function() + { + InspectorBackend.openInInspectedWindow(this._resource.url); + }, + get selectable() { if (!this._panel._viewingResourceMode) return false; - if (!this._panel._hiddenCategories.all) - return true; - if (this._panel._hiddenCategories[this._resource.category.name]) - return false; - return true; + return !this.isFilteredOut(); }, _createDivInTD: function(columnIdentifier) @@ -1668,6 +1719,16 @@ WebInspector.NetworkTotalGridNode = function(element) } WebInspector.NetworkTotalGridNode.prototype = { + isFilteredOut: function() + { + return false; + }, + + get selectable() + { + return false; + }, + createCells: function() { var td = document.createElement("td"); diff --git a/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js b/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js index e4794f3..88fddd6 100644 --- a/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js +++ b/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js @@ -180,7 +180,13 @@ WebInspector.ObjectPropertyTreeElement.prototype = { this.valueElement = document.createElement("span"); this.valueElement.className = "value"; - this.valueElement.textContent = this.property.value.description; + + var description = this.property.value.description; + // Render \n as a nice unicode cr symbol. + if (this.property.value.type === "string" && typeof description === "string") + description = description.replace(/\n/g, "\u21B5"); + this.valueElement.textContent = description; + if (this.property.isGetter) this.valueElement.addStyleClass("dimmed"); if (this.property.value.isError()) @@ -188,7 +194,7 @@ WebInspector.ObjectPropertyTreeElement.prototype = { if (this.property.value.type) this.valueElement.addStyleClass("console-formatted-" + this.property.value.type); if (this.property.value.type === "node") - this.valueElement.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true); + this.valueElement.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), false); this.listItemElement.removeChildren(); @@ -203,8 +209,7 @@ WebInspector.ObjectPropertyTreeElement.prototype = { function selectNode(nodeId) { if (nodeId) { - WebInspector.currentPanel = WebInspector.panels.elements; - WebInspector.panels.elements.focusedDOMNode = WebInspector.domAgent.nodeForId(nodeId); + WebInspector.panels.elements.switchToAndFocus(WebInspector.domAgent.nodeForId(nodeId)); } } diff --git a/Source/WebCore/inspector/front-end/PleaseWaitMessage.js b/Source/WebCore/inspector/front-end/PleaseWaitMessage.js new file mode 100644 index 0000000..54d805d --- /dev/null +++ b/Source/WebCore/inspector/front-end/PleaseWaitMessage.js @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.PleaseWaitMessage = function() +{ + this.element = document.createElement("div"); + this.element.className = "please-wait-msg"; + this.element.textContent = WebInspector.UIString("Please wait\u2026"); + + this.cancelButton = document.createElement("button"); + this.cancelButton.textContent = WebInspector.UIString("Cancel"); + this.cancelButton.addEventListener("click", this._cancelClicked.bind(this), false); +} + +WebInspector.PleaseWaitMessage.prototype = { + _cancelClicked: function() + { + if (this._cancelCallback) { + var cancelCallback = this._cancelCallback; + delete this._cancelCallback; + cancelCallback(); + } + }, + + hide: function() + { + var instance = WebInspector.PleaseWaitMessage.prototype.instance; + var message = instance.element; + if (message.parentNode) + message.parentNode.removeChild(message); + }, + + get instance() + { + if (!"_instance" in WebInspector.PleaseWaitMessage.prototype) + WebInspector.PleaseWaitMessage.prototype._instance = new WebInspector.PleaseWaitMessage(); + return WebInspector.PleaseWaitMessage.prototype._instance; + }, + + show: function(element, cancelCallback) + { + var instance = WebInspector.PleaseWaitMessage.prototype.instance; + var message = instance.element; + if (message.parentNode === element) + return; + else if (message.parentNode) + message.parentNode.removeChild(message); + if (message.childNodes.length > 1) + message.removeChild(instance.cancelButton); + if (cancelCallback) { + message.appendChild(instance.cancelButton); + instance._cancelCallback = cancelCallback; + } + element.appendChild(message); + }, + + startAction: function(element, actionCallback, cancelCallback) + { + var instance = WebInspector.PleaseWaitMessage.prototype.instance; + var message = instance.element; + if (message.parentNode === element) { + actionCallback(); + return; + } + + function doAction() + { + try { + actionCallback(); + } finally { + if (message.parentNode) + message.parentNode.removeChild(message); + } + } + + WebInspector.PleaseWaitMessage.prototype.show(element, cancelCallback); + setTimeout(doAction, 0); + } +}; + diff --git a/Source/WebCore/inspector/front-end/ProfilesPanel.js b/Source/WebCore/inspector/front-end/ProfilesPanel.js index 2e0ab28..b87ea7f 100644 --- a/Source/WebCore/inspector/front-end/ProfilesPanel.js +++ b/Source/WebCore/inspector/front-end/ProfilesPanel.js @@ -112,7 +112,7 @@ WebInspector.ProfilesPanel = function() this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item"); this.enableToggleButton.addEventListener("click", this._toggleProfiling.bind(this), false); - this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear CPU profiles."), "clear-status-bar-item"); + this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear all profiles."), "clear-status-bar-item"); this.clearResultsButton.addEventListener("click", this._clearProfiles.bind(this), false); this.profileViewStatusBarItemsContainer = document.createElement("div"); @@ -195,7 +195,7 @@ WebInspector.ProfilesPanel.prototype = { this._profiles = []; this._profilesIdMap = {}; this._profileGroups = {}; - this._profileGroupsForLinks = {} + this._profileGroupsForLinks = {}; this._profilesWereRequested = false; this.sidebarTreeElement.removeStyleClass("some-expandable"); @@ -259,6 +259,13 @@ WebInspector.ProfilesPanel.prototype = { _addProfileHeader: function(profile) { + if (this.hasTemporaryProfile(profile.typeId)) { + if (profile.typeId === WebInspector.CPUProfileType.TypeId) + this._removeProfileHeader(this._temporaryRecordingProfile); + else + this._removeProfileHeader(this._temporaryTakingSnapshot); + } + var typeId = profile.typeId; var profileType = this.getProfileType(typeId); var sidebarParent = profileType.treeElement; @@ -308,6 +315,7 @@ WebInspector.ProfilesPanel.prototype = { } var profileTreeElement = profileType.createSidebarTreeElementForProfile(profile); + profile.sideBarElement = profileTreeElement; profileTreeElement.small = small; if (alternateTitle) profileTreeElement.mainTitle = alternateTitle; @@ -370,17 +378,20 @@ WebInspector.ProfilesPanel.prototype = { this.profileViewStatusBarItemsContainer.removeChildren(); var statusBarItems = view.statusBarItems; - for (var i = 0; i < statusBarItems.length; ++i) - this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]); + if (statusBarItems) + for (var i = 0; i < statusBarItems.length; ++i) + this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]); }, getProfiles: function(typeId) { var result = []; var profilesCount = this._profiles.length; - for (var i = 0; i < profilesCount; ++i) - if (this._profiles[i].typeId === typeId) - result.push(this._profiles[i]); + for (var i = 0; i < profilesCount; ++i) { + var profile = this._profiles[i]; + if (!profile.isTemporary && profile.typeId === typeId) + result.push(profile); + } return result; }, @@ -398,17 +409,6 @@ WebInspector.ProfilesPanel.prototype = { return !!this._profilesIdMap[this._makeKey(profile.uid, profile.typeId)]; }, - updateProfile: function(profile) - { - var profilesCount = this._profiles.length; - for (var i = 0; i < profilesCount; ++i) - if (this._profiles[i].typeId === profile.typeId - && this._profiles[i].uid === profile.uid) { - this._profiles[i] = profile; - break; - } - }, - loadHeapSnapshot: function(uid, callback) { var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)]; @@ -423,6 +423,7 @@ WebInspector.ProfilesPanel.prototype = { profile._is_loading = true; profile._callbacks = [callback]; profile._json = ""; + profile.sideBarElement.subtitle = WebInspector.UIString("Loading…"); InspectorBackend.getProfile(profile.typeId, profile.uid); } }, @@ -444,13 +445,23 @@ WebInspector.ProfilesPanel.prototype = { var callbacks = profile._callbacks; delete profile._callbacks; - var loadedSnapshot = JSON.parse(profile._json); - delete profile._json; - delete profile._is_loading; - profile._loaded = true; - WebInspector.HeapSnapshotView.prototype.processLoadedSnapshot(profile, loadedSnapshot); - for (var i = 0; i < callbacks.length; ++i) - callbacks[i](profile); + profile.sideBarElement.subtitle = WebInspector.UIString("Parsing…"); + window.setTimeout(doParse, 0); + + function doParse() + { + var loadedSnapshot = JSON.parse(profile._json); + delete profile._json; + delete profile._is_loading; + profile._loaded = true; + profile.sideBarElement.subtitle = ""; + if (!Preferences.detailedHeapProfiles) + WebInspector.HeapSnapshotView.prototype.processLoadedSnapshot(profile, loadedSnapshot); + else + WebInspector.DetailedHeapshotView.prototype.processLoadedSnapshot(profile, loadedSnapshot); + for (var i = 0; i < callbacks.length; ++i) + callbacks[i](profile); + } }, showView: function(view) @@ -579,10 +590,13 @@ WebInspector.ProfilesPanel.prototype = { _toggleProfiling: function(optionalAlways) { - if (this._profilerEnabled) + if (this._profilerEnabled) { + WebInspector.settings.profilerEnabled = false; InspectorBackend.disableProfiler(true); - else - InspectorBackend.enableProfiler(!!optionalAlways); + } else { + WebInspector.settings.profilerEnabled = !!optionalAlways; + InspectorBackend.enableProfiler(); + } }, _populateProfiles: function() @@ -629,6 +643,31 @@ WebInspector.ProfilesPanel.prototype = { this._removeProfileHeader(this._temporaryRecordingProfile); } this.updateProfileTypeButtons(); + }, + + takeHeapSnapshot: function(detailed) + { + if (!this.hasTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId)) { + if (!this._temporaryTakingSnapshot) { + this._temporaryTakingSnapshot = { + typeId: WebInspector.HeapSnapshotProfileType.TypeId, + title: WebInspector.UIString("Snapshotting…"), + uid: -1, + isTemporary: true + }; + } + this._addProfileHeader(this._temporaryTakingSnapshot); + } + InspectorBackend.takeHeapSnapshot(detailed); + }, + + _reportHeapSnapshotProgress: function(done, total) + { + if (this.hasTemporaryProfile(WebInspector.HeapSnapshotProfileType.TypeId)) { + this._temporaryTakingSnapshot.sideBarElement.subtitle = WebInspector.UIString("%.2f%%", (done / total) * 100); + if (done >= total) + this._removeProfileHeader(this._temporaryTakingSnapshot); + } } } @@ -674,6 +713,11 @@ WebInspector.ProfilerDispatcher.prototype = { setRecordingProfile: function(isProfiling) { this._profiler._setRecordingProfile(isProfiling); + }, + + reportHeapSnapshotProgress: function(done, total) + { + this._profiler._reportHeapSnapshotProgress(done, total); } } @@ -717,16 +761,6 @@ WebInspector.ProfileSidebarTreeElement.prototype = { this.refreshTitles(); }, - get subtitle() - { - // There is no subtitle. - }, - - set subtitle(x) - { - // Can't change subtitle. - }, - set searchMatches(matches) { if (!matches) { diff --git a/Source/WebCore/inspector/front-end/Resource.js b/Source/WebCore/inspector/front-end/Resource.js index 00c1fb9..6cf5b9c 100644 --- a/Source/WebCore/inspector/front-end/Resource.js +++ b/Source/WebCore/inspector/front-end/Resource.js @@ -31,9 +31,9 @@ WebInspector.Resource = function(identifier, url) this.url = url; this._startTime = -1; this._endTime = -1; - this._requestMethod = ""; this._category = WebInspector.resourceCategories.other; this._pendingContentCallbacks = []; + this._responseHeadersSize = 0; } // Keep these in sync with WebCore::InspectorResource::Type @@ -237,8 +237,21 @@ WebInspector.Resource.prototype = { get transferSize() { - // FIXME: this is wrong for chunked-encoding resources. - return this.cached ? 0 : Number(this.responseHeaders["Content-Length"] || this.resourceSize || 0); + if (this.cached) + return 0; + if (this.statusCode === 304) // Not modified + return this._responseHeadersSize; + // FIXME: We prefer using Content-Length over resourceSize as + // resourceSize may differ from actual transfer size if platform's + // network stack performed decoding (e.g. gzip decompression). + // The Content-Length, though, is expected to come from raw + // response headers and will reflect actual transfer length. + // This won't work for chunked content encoding, so fall back to + // resourceSize when we don't have Content-Length. This still won't + // work for chunks with non-trivial encodings. We need a way to + // get actaul transfer size from the network stack. + var bodySize = Number(this.responseHeaders["Content-Length"] || this.resourceSize); + return this._responseHeadersSize + bodySize; }, get expectedContentLength() @@ -303,7 +316,6 @@ WebInspector.Resource.prototype = { delete this._timing; }, - get timing() { return this._timing; @@ -431,6 +443,8 @@ WebInspector.Resource.prototype = { set responseHeaders(x) { this._responseHeaders = x; + // FIXME: we should take actual headers size from network stack, when possible. + this._responseHeadersSize = this._headersSize(x); delete this._sortedResponseHeaders; delete this._responseCookies; @@ -512,6 +526,14 @@ WebInspector.Resource.prototype = { } }, + _headersSize: function(headers) + { + var size = 0; + for (var header in headers) + size += header.length + headers[header].length + 3; // _typical_ overhead per herader is ": ".length + "\n".length. + return size; + }, + get errors() { return this._errors || 0; @@ -550,9 +572,9 @@ WebInspector.Resource.prototype = { return true; if (typeof this.type === "undefined" - || this.type === WebInspector.Resource.Type.Other - || this.type === WebInspector.Resource.Type.XHR - || this.type === WebInspector.Resource.Type.WebSocket) + || this.type === WebInspector.Resource.Type.Other + || this.type === WebInspector.Resource.Type.XHR + || this.type === WebInspector.Resource.Type.WebSocket) return true; if (!this.mimeType) @@ -671,8 +693,8 @@ WebInspector.Resource.prototype = { callback(null, null); return; } - if (this._content) { - callback(this._content, this._contentEncoded); + if (typeof this._content !== "undefined") { + callback(this.content, this._contentEncoded); return; } this._pendingContentCallbacks.push(callback); @@ -697,7 +719,7 @@ WebInspector.Resource.prototype = { { const maxDataUrlSize = 1024 * 1024; // If resource content is not available or won't fit a data URL, fall back to using original URL. - if (!this._content || this._content.length > maxDataUrlSize) + if (this._content == null || this._content.length > maxDataUrlSize) return this.url; return "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content; @@ -719,7 +741,7 @@ WebInspector.Resource.prototype = { this._pendingContentCallbacks.length = 0; delete this._contentRequested; } - WebInspector.NetworkManager.requestContent(this, this._contentEncoded, onResourceContent.bind(this)); + WebInspector.networkManager.requestContent(this, this._contentEncoded, onResourceContent.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/ResourceTreeModel.js b/Source/WebCore/inspector/front-end/ResourceTreeModel.js index b114b94..da2d47a 100644 --- a/Source/WebCore/inspector/front-end/ResourceTreeModel.js +++ b/Source/WebCore/inspector/front-end/ResourceTreeModel.js @@ -31,16 +31,17 @@ WebInspector.ResourceTreeModel = function() { - this.reloadCachedResources(); + this.reset(); } WebInspector.ResourceTreeModel.prototype = { - reloadCachedResources: function() + reset: function() { this._resourcesByURL = {}; this._resourcesByFrameId = {}; this._subframes = {}; - InspectorBackend.cachedResources(this._processCachedResources.bind(this)); + if (WebInspector.panels) + WebInspector.panels.resources.clear(); }, addOrUpdateFrame: function(frame) @@ -81,6 +82,7 @@ WebInspector.ResourceTreeModel.prototype = { this._resourcesByFrameId[frameId] = resourcesForFrame; } resourcesForFrame.push(resource); + this._bindResourceURL(resource); WebInspector.panels.resources.addResourceToFrame(frameId, resource); }, @@ -128,7 +130,7 @@ WebInspector.ResourceTreeModel.prototype = { return entry; }, - bindResourceURL: function(resource) + _bindResourceURL: function(resource) { var resourceForURL = this._resourcesByURL[resource.url]; if (!resourceForURL) @@ -168,7 +170,7 @@ WebInspector.ResourceTreeModel.prototype = { preservedResourcesForFrame.push(resource); continue; } - this.unbindResourceURL(resource); + this._unbindResourceURL(resource); } delete this._resourcesByFrameId[frameId]; @@ -194,7 +196,7 @@ WebInspector.ResourceTreeModel.prototype = { return false; }, - unbindResourceURL: function(resource) + _unbindResourceURL: function(resource) { var resourceForURL = this._resourcesByURL[resource.url]; if (!resourceForURL) @@ -208,52 +210,5 @@ WebInspector.ResourceTreeModel.prototype = { } delete this._resourcesByURL[resource.url]; - }, - - _processCachedResources: function(mainFramePayload) - { - var mainResource = this._addFramesRecursively(mainFramePayload); - WebInspector.mainResource = mainResource; - mainResource.isMainResource = true; - }, - - _addFramesRecursively: function(framePayload) - { - var frameResource = this.createResource(null, framePayload.resource.url, framePayload.resource.loader); - WebInspector.NetworkManager.updateResourceWithRequest(frameResource, framePayload.resource.request); - WebInspector.NetworkManager.updateResourceWithResponse(frameResource, framePayload.resource.response); - frameResource.type = WebInspector.Resource.Type["Document"]; - frameResource.finished = true; - - this.addOrUpdateFrame(framePayload); - this.addResourceToFrame(framePayload.id, frameResource); - - for (var i = 0; framePayload.children && i < framePayload.children.length; ++i) - this._addFramesRecursively(framePayload.children[i]); - - if (!framePayload.subresources) - return; - - for (var i = 0; i < framePayload.subresources.length; ++i) { - var cachedResource = framePayload.subresources[i]; - var resource = this.createResource(null, cachedResource.url, cachedResource.loader); - WebInspector.NetworkManager.updateResourceWithCachedResource(resource, cachedResource); - resource.finished = true; - this.addResourceToFrame(framePayload.id, resource); - } - return frameResource; - }, - - createResource: function(identifier, url, loader, stackTrace) - { - var resource = new WebInspector.Resource(identifier, url); - resource.loader = loader; - if (loader) { - resource.documentURL = loader.url; - this.bindResourceURL(resource); - } - resource.stackTrace = stackTrace; - - return resource; } } diff --git a/Source/WebCore/inspector/front-end/ResourceView.js b/Source/WebCore/inspector/front-end/ResourceView.js index b69097d..e38cd0a 100644 --- a/Source/WebCore/inspector/front-end/ResourceView.js +++ b/Source/WebCore/inspector/front-end/ResourceView.js @@ -50,7 +50,11 @@ WebInspector.ResourceView.createResourceView = function(resource) case WebInspector.resourceCategories.stylesheets: case WebInspector.resourceCategories.scripts: case WebInspector.resourceCategories.xhr: - return new WebInspector.SourceView(resource); + var contentProvider = new WebInspector.SourceFrameContentProviderForResource(resource); + var isScript = resource.type === WebInspector.Resource.Type.Script; + var view = new WebInspector.SourceFrame(contentProvider, resource.url, isScript); + view.resource = resource; + return view; case WebInspector.resourceCategories.images: return new WebInspector.ImageView(resource); case WebInspector.resourceCategories.fonts: @@ -68,7 +72,7 @@ WebInspector.ResourceView.resourceViewTypeMatchesResource = function(resource) case WebInspector.resourceCategories.stylesheets: case WebInspector.resourceCategories.scripts: case WebInspector.resourceCategories.xhr: - return resourceView.__proto__ === WebInspector.SourceView.prototype; + return resourceView.__proto__ === WebInspector.SourceFrame.prototype; case WebInspector.resourceCategories.images: return resourceView.__proto__ === WebInspector.ImageView.prototype; case WebInspector.resourceCategories.fonts: @@ -105,7 +109,6 @@ WebInspector.ResourceView.recreateResourceView = function(resource) if (scrollTop) newView.scrollTop = scrollTop; - WebInspector.panels.scripts.viewRecreated(oldView, newView); return newView; } @@ -115,3 +118,37 @@ WebInspector.ResourceView.existingResourceViewForResource = function(resource) return null; return resource._resourcesView; } + + +WebInspector.SourceFrameContentProviderForResource = function(resource) +{ + WebInspector.SourceFrameContentProvider.call(this); + this._resource = resource; +} + +//This is a map from resource.type to mime types +//found in WebInspector.SourceTokenizer.Registry. +WebInspector.SourceFrameContentProviderForResource.DefaultMIMETypeForResourceType = { + 0: "text/html", + 1: "text/css", + 4: "text/javascript" +} + +WebInspector.SourceFrameContentProviderForResource.prototype = { + requestContent: function(callback) + { + function contentLoaded(content) + { + var mimeType = WebInspector.SourceFrameContentProviderForResource.DefaultMIMETypeForResourceType[this._resource.type] || this._resource.mimeType; + callback(mimeType, content); + } + this._resource.requestContent(contentLoaded.bind(this)); + }, + + scripts: function() + { + return WebInspector.debuggerModel.scriptsForURL(this._resource.url); + } +} + +WebInspector.SourceFrameContentProviderForResource.prototype.__proto__ = WebInspector.SourceFrameContentProvider.prototype; diff --git a/Source/WebCore/inspector/front-end/ResourcesPanel.js b/Source/WebCore/inspector/front-end/ResourcesPanel.js index 7e1fcc0..7c0649f 100644 --- a/Source/WebCore/inspector/front-end/ResourcesPanel.js +++ b/Source/WebCore/inspector/front-end/ResourcesPanel.js @@ -56,12 +56,6 @@ WebInspector.ResourcesPanel = function(database) this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "ApplicationCache", "application-cache-storage-tree-item"); this.sidebarTree.appendChild(this.applicationCacheListTreeElement); - if (Preferences.fileSystemEnabled) { - this.fileSystemListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("File System"), "FileSystem", "file-system-storage-tree-item"); - this.sidebarTree.appendChild(this.fileSystemListTreeElement); - this.fileSystemListTreeElement.expand(); - } - this.storageViews = document.createElement("div"); this.storageViews.id = "storage-views"; this.storageViews.className = "diff-container"; @@ -102,9 +96,19 @@ WebInspector.ResourcesPanel.prototype = { { WebInspector.Panel.prototype.show.call(this); - if (this.visibleView instanceof WebInspector.ResourceView) + if (this.visibleView && this.visibleView.resource) this._showResourceView(this.visibleView.resource); + this._initDefaultSelection(); + }, + + loadEventFired: function() + { + this._initDefaultSelection(); + }, + + _initDefaultSelection: function() + { if (this._initializedDefaultSelection) return; @@ -119,17 +123,14 @@ WebInspector.ResourcesPanel.prototype = { } } } - this._initDefaultSelection(); - }, - _initDefaultSelection: function() - { if (WebInspector.mainResource && this.resourcesListTreeElement && this.resourcesListTreeElement.expanded) this.showResource(WebInspector.mainResource); }, reset: function() { + delete this._initializedDefaultSelection; this._origins = {}; this._domains = {}; for (var i = 0; i < this._databases.length; ++i) { @@ -147,7 +148,6 @@ WebInspector.ResourcesPanel.prototype = { this._domStorage = []; this._cookieViews = {}; - this._fileSystemView = null; this._applicationCacheView = null; delete this._cachedApplicationCacheViewStatus; @@ -157,8 +157,6 @@ WebInspector.ResourcesPanel.prototype = { this.sessionStorageListTreeElement.removeChildren(); this.cookieListTreeElement.removeChildren(); this.applicationCacheListTreeElement.removeChildren(); - if (Preferences.fileSystemEnabled) - this.fileSystemListTreeElement.removeChildren(); this.storageViews.removeChildren(); this.storageViewStatusBarItemsContainer.removeChildren(); @@ -170,6 +168,7 @@ WebInspector.ResourcesPanel.prototype = { clear: function() { this.resourcesListTreeElement.removeChildren(); + this._treeElementForFrameId = {}; this.reset(); }, @@ -291,16 +290,6 @@ WebInspector.ResourcesPanel.prototype = { var applicationCacheTreeElement = new WebInspector.ApplicationCacheTreeElement(this, domain); this.applicationCacheListTreeElement.appendChild(applicationCacheTreeElement); } - - if (Preferences.fileSystemEnabled) { - // FIXME: This should match the SecurityOrigin::toString(), add a test for this. - var securityOrigin = parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : ""); - if (!this._origins[securityOrigin]) { - this._origins[securityOrigin] = true; - var fileSystemTreeElement = new WebInspector.FileSystemTreeElement(this, securityOrigin); - this.fileSystemListTreeElement.appendChild(fileSystemTreeElement); - } - } }, addDOMStorage: function(domStorage) @@ -338,12 +327,12 @@ WebInspector.ResourcesPanel.prototype = { canShowSourceLine: function(url, line) { - return !!WebInspector.resourceTreeModel.resourceForURL(url); + return !!WebInspector.resourceForURL(url); }, showSourceLine: function(url, line) { - var resource = WebInspector.resourceTreeModel.resourceForURL(url); + var resource = WebInspector.resourceForURL(url); if (resource.type === WebInspector.Resource.Type.XHR) { // Show XHRs in the network panel only. if (WebInspector.panels.network && WebInspector.panels.network.canShowSourceLine(url, line)) { @@ -352,7 +341,7 @@ WebInspector.ResourcesPanel.prototype = { } return; } - this.showResource(WebInspector.resourceTreeModel.resourceForURL(url), line); + this.showResource(WebInspector.resourceForURL(url), line); }, showResource: function(resource, line) @@ -378,7 +367,7 @@ WebInspector.ResourcesPanel.prototype = { var view = WebInspector.ResourceView.resourceViewForResource(resource); // Consider rendering diff markup here. - if (resource.baseRevision && view instanceof WebInspector.SourceView) { + if (resource.baseRevision && view instanceof WebInspector.SourceFrame) { function callback(baseContent) { if (baseContent) @@ -413,7 +402,7 @@ WebInspector.ResourcesPanel.prototype = { } else offset = i - right[i].row; } - view.sourceFrame.markDiff(diffData); + view.markDiff(diffData); }, showDatabase: function(database, tableName) @@ -481,12 +470,6 @@ WebInspector.ResourcesPanel.prototype = { this._applicationCacheView.updateStatus(this._cachedApplicationCacheViewStatus); }, - showFileSystem: function(treeElement, origin) - { - this._fileSystemView = new WebInspector.FileSystemView(treeElement, origin); - this._innerShowView(this._fileSystemView); - }, - showCategoryView: function(categoryName) { if (!this._categoryView) @@ -635,24 +618,6 @@ WebInspector.ResourcesPanel.prototype = { this._applicationCacheView.updateStatus(status); }, - updateFileSystemPath: function(root, type, origin) - { - if (this._fileSystemView && this._fileSystemView === this.visibleView) - this._fileSystemView.updateFileSystemPath(root, type, origin); - }, - - updateFileSystemError: function(type, origin) - { - if (this._fileSystemView && this._fileSystemView === this.visibleView) - this._fileSystemView.updateFileSystemError(type, origin); - }, - - setFileSystemDisabled: function() - { - if (this._fileSystemView && this._fileSystemView === this.visibleView) - this._fileSystemView.setFileSystemDisabled(); - }, - updateNetworkState: function(isNowOnline) { if (this._applicationCacheView && this._applicationCacheView === this.visibleView) @@ -690,7 +655,7 @@ WebInspector.ResourcesPanel.prototype = { var views = []; const visibleView = this.visibleView; - if (visibleView instanceof WebInspector.ResourceView && visibleView.performSearch) + if (visibleView.performSearch) views.push(visibleView); function callback(resourceTreeElement) @@ -1076,7 +1041,7 @@ WebInspector.FrameResourceTreeElement.prototype = { _errorsWarningsUpdated: function() { - // FIXME: move to the Script/SourceView. + // FIXME: move to the SourceFrame. if (!this._resource.warnings && !this._resource.errors) { var view = WebInspector.ResourceView.existingResourceViewForResource(this._resource); if (view && view.clearMessages) @@ -1275,27 +1240,6 @@ WebInspector.ResourceRevisionTreeElement.prototype = { WebInspector.ResourceRevisionTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype; -WebInspector.FileSystemTreeElement = function(storagePanel, origin) -{ - WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, origin, "file-system-storage-tree-item"); - this._origin = origin; -} - -WebInspector.FileSystemTreeElement.prototype = { - get itemURL() - { - return "file-system://" + encodeURI(this._origin); - }, - - onselect: function() - { - WebInspector.BaseStorageTreeElement.prototype.onselect.call(this); - this._storagePanel.showFileSystem(this, this._origin); - } -} - -WebInspector.FileSystemTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype; - WebInspector.StorageCategoryView = function() { WebInspector.View.call(this); diff --git a/Source/WebCore/inspector/front-end/ScopeChainSidebarPane.js b/Source/WebCore/inspector/front-end/ScopeChainSidebarPane.js index d3190a9..bdbb0cf 100644 --- a/Source/WebCore/inspector/front-end/ScopeChainSidebarPane.js +++ b/Source/WebCore/inspector/front-end/ScopeChainSidebarPane.js @@ -26,6 +26,8 @@ WebInspector.ScopeChainSidebarPane = function() { WebInspector.SidebarPane.call(this, WebInspector.UIString("Scope Variables")); + this._sections = []; + this._expandedSections = {}; this._expandedProperties = []; } @@ -34,9 +36,6 @@ WebInspector.ScopeChainSidebarPane.prototype = { { this.bodyElement.removeChildren(); - this.sections = []; - this.callFrame = callFrame; - if (!callFrame) { var infoElement = document.createElement("div"); infoElement.className = "info"; @@ -45,6 +44,18 @@ WebInspector.ScopeChainSidebarPane.prototype = { return; } + for (var i = 0; i < this._sections.length; ++i) { + var section = this._sections[i]; + if (!section.title) + continue; + if (section.expanded) + this._expandedSections[section.title] = true; + else + delete this._expandedSections[section.title]; + } + + this._sections = []; + var foundLocalScope = false; var scopeChain = callFrame.scopeChain; for (var i = 0; i < scopeChain.length; ++i) { @@ -81,10 +92,10 @@ WebInspector.ScopeChainSidebarPane.prototype = { section.editInSelectedCallFrameWhenPaused = true; section.pane = this; - if (!foundLocalScope || scopeObjectProxy.isLocal) + if (!foundLocalScope || scopeObjectProxy.isLocal || title in this._expandedSections) section.expanded = true; - this.sections.push(section); + this._sections.push(section); this.bodyElement.appendChild(section.element); } } diff --git a/Source/WebCore/inspector/front-end/Script.js b/Source/WebCore/inspector/front-end/Script.js index 6e3b18d..8d3eabf 100644 --- a/Source/WebCore/inspector/front-end/Script.js +++ b/Source/WebCore/inspector/front-end/Script.js @@ -78,7 +78,7 @@ WebInspector.Script.prototype = { { function extractSourceLine() { - lineNumber -= this.startingLine; + lineNumber -= this.lineOffset; callback(this._source.substring(this._lineEndings[lineNumber - 1], this._lineEndings[lineNumber])); } diff --git a/Source/WebCore/inspector/front-end/ScriptFormatter.js b/Source/WebCore/inspector/front-end/ScriptFormatter.js index 69ffb74..5c00e51 100644 --- a/Source/WebCore/inspector/front-end/ScriptFormatter.js +++ b/Source/WebCore/inspector/front-end/ScriptFormatter.js @@ -28,107 +28,117 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.ScriptFormatter = function(source) +WebInspector.ScriptFormatter = function() { - this._originalSource = source; - this._originalLineEndings = source.findAll("\n"); - this._originalLineEndings.push(source.length); -} - -WebInspector.ScriptFormatter.locationToPosition = function(lineEndings, location) -{ - var position = location.line ? lineEndings[location.line - 1] + 1 : 0; - return position + location.column; -} - -WebInspector.ScriptFormatter.positionToLocation = function(lineEndings, position) -{ - var location = {}; - location.line = lineEndings.upperBound(position - 1); - if (!location.line) - location.column = position; - else - location.column = position - lineEndings[location.line - 1] - 1; - return location; + this._worker = new Worker("ScriptFormatterWorker.js"); + this._worker.onmessage = this._handleMessage.bind(this); + this._worker.onerror = this._handleError.bind(this); + this._tasks = []; } WebInspector.ScriptFormatter.prototype = { - format: function(callback) + formatContent: function(content, callback) { - var worker = new Worker("scriptFormatterWorker.js"); - function messageHandler(event) + var chunks = this._splitContentIntoChunks(content.text, content.scriptRanges); + + function didFormatChunks() { - var formattedSource = event.data; - this._formatted = true; - this._formattedSource = formattedSource; - this._formattedLineEndings = formattedSource.findAll("\n"); - this._formattedLineEndings.push(formattedSource.length); - this._buildMapping(); - callback(formattedSource); + var result = this._buildContentFromChunks(chunks); + callback(new WebInspector.FormattedSourceFrameContent(content, result.text, result.mapping)); } - worker.onmessage = messageHandler.bind(this); - worker.postMessage(this._originalSource); + this._formatChunks(chunks, 0, didFormatChunks.bind(this)); }, - _buildMapping: function() + _splitContentIntoChunks: function(text, scriptRanges) { - this._originalSymbolPositions = []; - this._formattedSymbolPositions = []; - var lastCodePosition = 0; - var regexp = /[\$\.\w]+|{|}|;/g; - while (true) { - var match = regexp.exec(this._formattedSource); - if (!match) - break; - var position = this._originalSource.indexOf(match[0], lastCodePosition); - if (position === -1) - continue; - this._originalSymbolPositions.push(position); - this._formattedSymbolPositions.push(match.index); - lastCodePosition = position + match[0].length; + var chunks = []; + function addChunk(start, end, isScript) + { + var chunk = {}; + chunk.start = start; + chunk.end = end; + chunk.isScript = isScript; + chunk.text = text.substring(start, end); + chunks.push(chunk); + } + var currentPosition = 0; + for (var i = 0; i < scriptRanges.length; ++i) { + var scriptRange = scriptRanges[i]; + if (currentPosition < scriptRange.start) + addChunk(currentPosition, scriptRange.start, false); + addChunk(scriptRange.start, scriptRange.end, true); + currentPosition = scriptRange.end; } - this._originalSymbolPositions.push(this._originalSource.length); - this._formattedSymbolPositions.push(this._formattedSource.length); + if (currentPosition < text.length) + addChunk(currentPosition, text.length, false); + return chunks; }, - originalLineNumberToFormattedLineNumber: function(originalLineNumber) + _formatChunks: function(chunks, index, callback) { - if (!this._formatted) - return originalLineNumber; - var originalPosition = WebInspector.ScriptFormatter.locationToPosition(this._originalLineEndings, { line: originalLineNumber, column: 0 }); - return this.originalPositionToFormattedLineNumber(originalPosition); + while(true) { + if (index === chunks.length) { + callback(); + return; + } + var chunk = chunks[index++]; + if (chunk.isScript) + break; + } + + function didFormat(formattedSource, mapping) + { + chunk.text = formattedSource; + chunk.mapping = mapping; + this._formatChunks(chunks, index, callback); + } + this._formatScript(chunk.text, didFormat.bind(this)); }, - formattedLineNumberToOriginalLineNumber: function(formattedLineNumber) + _buildContentFromChunks: function(chunks) { - if (!this._formatted) - return formattedLineNumber; - var originalPosition = this.formattedLineNumberToOriginalPosition(formattedLineNumber); - return WebInspector.ScriptFormatter.positionToLocation(this._originalLineEndings, originalPosition).line; + var text = ""; + var mapping = { original: [], formatted: [] }; + for (var i = 0; i < chunks.length; ++i) { + var chunk = chunks[i]; + mapping.original.push(chunk.start); + mapping.formatted.push(text.length); + if (chunk.isScript) { + if (text) + text += "\n"; + for (var j = 0; j < chunk.mapping.original.length; ++j) { + mapping.original.push(chunk.mapping.original[j] + chunk.start); + mapping.formatted.push(chunk.mapping.formatted[j] + text.length); + } + text += chunk.text; + } else { + if (text) + text += "\n"; + text += chunk.text; + } + mapping.original.push(chunk.end); + mapping.formatted.push(text.length); + } + return { text: text, mapping: mapping }; }, - originalPositionToFormattedLineNumber: function(originalPosition) + _formatScript: function(source, callback) { - var lineEndings = this._formatted ? this._formattedLineEndings : this._originalLineEndings; - if (this._formatted) - formattedPosition = this._convertPosition(this._originalSymbolPositions, this._formattedSymbolPositions, originalPosition); - return WebInspector.ScriptFormatter.positionToLocation(lineEndings, formattedPosition).line; + this._tasks.push({ source: source, callback: callback }); + this._worker.postMessage(source); }, - formattedLineNumberToOriginalPosition: function(formattedLineNumber) + _handleMessage: function(event) { - var lineEndings = this._formatted ? this._formattedLineEndings : this._originalLineEndings; - var formattedPosition = WebInspector.ScriptFormatter.locationToPosition(lineEndings, { line: formattedLineNumber, column: 0 }); - if (!this._formatted) - return formattedPosition; - return this._convertPosition(this._formattedSymbolPositions, this._originalSymbolPositions, formattedPosition); + var task = this._tasks.shift(); + task.callback(event.data.formattedSource, event.data.mapping); }, - _convertPosition: function(symbolPositions1, symbolPositions2, position) + _handleError: function(event) { - var index = symbolPositions1.upperBound(position); - if (index === symbolPositions2.length - 1) - return symbolPositions2[index] - 1; - return symbolPositions2[index]; + console.warn("Error in script formatter worker:", event); + event.preventDefault() + var task = this._tasks.shift(); + task.callback(task.source, { original: [], formatted: [] }); } } diff --git a/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js b/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js index e900317..1a4c28e 100644 --- a/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js +++ b/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js @@ -32,7 +32,10 @@ var parse = loadModule("parse-js.js"); var process = loadModule("process.js"); onmessage = function(event) { - postMessage(beautify(event.data)); + var source = event.data; + var formattedSource = beautify(source); + var mapping = buildMapping(source, formattedSource); + postMessage({ formattedSource: formattedSource, mapping: mapping }); }; function beautify(source) @@ -47,6 +50,25 @@ function beautify(source) return process.gen_code(ast, beautifyOptions); } +function buildMapping(source, formattedSource) +{ + var mapping = { original: [], formatted: [] }; + var lastCodePosition = 0; + var regexp = /[\$\.\w]+|{|}/g; + while (true) { + var match = regexp.exec(formattedSource); + if (!match) + break; + var position = source.indexOf(match[0], lastCodePosition); + if (position === -1) + continue; + mapping.original.push(position); + mapping.formatted.push(match.index); + lastCodePosition = position + match[0].length; + } + return mapping; +} + function loadModule(src) { var request = new XMLHttpRequest(); diff --git a/Source/WebCore/inspector/front-end/ScriptView.js b/Source/WebCore/inspector/front-end/ScriptView.js deleted file mode 100644 index f631fcc..0000000 --- a/Source/WebCore/inspector/front-end/ScriptView.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.ScriptView = function(script) -{ - WebInspector.View.call(this); - - this.element.addStyleClass("script-view"); - - var contentProvider = new WebInspector.SourceFrameContentProviderForScript(script); - this.sourceFrame = new WebInspector.SourceFrame(this.element, contentProvider, "", true); -} - -WebInspector.ScriptView.prototype = { - // The following methods are pulled from SourceView, since they are - // generic and work with ScriptView just fine. - - show: WebInspector.SourceView.prototype.show, - hide: WebInspector.SourceView.prototype.hide, - revealLine: WebInspector.SourceView.prototype.revealLine, - highlightLine: WebInspector.SourceView.prototype.highlightLine, - addMessage: WebInspector.SourceView.prototype.addMessage, - clearMessages: WebInspector.SourceView.prototype.clearMessages, - searchCanceled: WebInspector.SourceView.prototype.searchCanceled, - performSearch: WebInspector.SourceView.prototype.performSearch, - jumpToFirstSearchResult: WebInspector.SourceView.prototype.jumpToFirstSearchResult, - jumpToLastSearchResult: WebInspector.SourceView.prototype.jumpToLastSearchResult, - jumpToNextSearchResult: WebInspector.SourceView.prototype.jumpToNextSearchResult, - jumpToPreviousSearchResult: WebInspector.SourceView.prototype.jumpToPreviousSearchResult, - showingFirstSearchResult: WebInspector.SourceView.prototype.showingFirstSearchResult, - showingLastSearchResult: WebInspector.SourceView.prototype.showingLastSearchResult, - _jumpToSearchResult: WebInspector.SourceView.prototype._jumpToSearchResult, - resize: WebInspector.SourceView.prototype.resize -} - -WebInspector.ScriptView.prototype.__proto__ = WebInspector.View.prototype; - - -WebInspector.SourceFrameContentProviderForScript = function(script) -{ - WebInspector.SourceFrameContentProvider.call(this); - this._script = script; -} - -WebInspector.SourceFrameContentProviderForScript.prototype = { - requestContent: function(callback) - { - if (this._script.source) { - callback("text/javascript", this._script.source); - return; - } - - function didRequestSource(content) - { - var source; - if (content) { - var prefix = ""; - for (var i = 0; i < this._script.startingLine - 1; ++i) - prefix += "\n"; - source = prefix + content; - } else - source = WebInspector.UIString("<source is not available>"); - callback("text/javascript", source); - } - this._script.requestSource(didRequestSource.bind(this)); - }, - - scripts: function() - { - return [this._script]; - } -} - -WebInspector.SourceFrameContentProviderForScript.prototype.__proto__ = WebInspector.SourceFrameContentProvider.prototype; diff --git a/Source/WebCore/inspector/front-end/ScriptsPanel.js b/Source/WebCore/inspector/front-end/ScriptsPanel.js index a74f80d..264291f 100644 --- a/Source/WebCore/inspector/front-end/ScriptsPanel.js +++ b/Source/WebCore/inspector/front-end/ScriptsPanel.js @@ -242,9 +242,7 @@ WebInspector.ScriptsPanel.prototype = { _parsedScriptSource: function(event) { - var sourceID = event.data; - var script = WebInspector.debuggerModel.scriptForSourceID(sourceID); - this._addScript(script); + this._addScript(event.data); }, _failedToParseScriptSource: function(event) @@ -257,16 +255,23 @@ WebInspector.ScriptsPanel.prototype = { var sourceID = event.data.sourceID; var oldSource = event.data.oldSource; + var oldView, newView; var script = WebInspector.debuggerModel.scriptForSourceID(sourceID); - var oldView = script._scriptView; - if (oldView) { - script._scriptView = new WebInspector.ScriptView(script); - this.viewRecreated(oldView, script._scriptView); - } if (script.resource) { + oldView = this._urlToSourceFrame[script.resource.url]; + delete this._urlToSourceFrame[script.resource.url]; + newView = this._sourceFrameForResource(script.resource); var revertHandle = WebInspector.debuggerModel.editScriptSource.bind(WebInspector.debuggerModel, sourceID, oldSource); script.resource.setContent(script.source, revertHandle); + } else { + var oldView = script._sourceFrame; + delete script._sourceFrame; + newView = this._sourceFrameForScript(script); } + newView.scrollTop = oldView.scrollTop; + + if (this.visibleView === oldView) + this.visibleView = newView; var callFrames = WebInspector.debuggerModel.callFrames; if (callFrames.length) @@ -275,7 +280,7 @@ WebInspector.ScriptsPanel.prototype = { _addScript: function(script) { - var resource = WebInspector.resourceForURL(script.sourceURL); + var resource = WebInspector.networkManager.inflightResourceForURL(script.sourceURL) || WebInspector.resourceForURL(script.sourceURL); if (resource) { if (resource.finished) { // Resource is finished, bind the script right away. @@ -295,17 +300,41 @@ WebInspector.ScriptsPanel.prototype = { _resourceLoadingFinished: function(e) { var resource = e.target; + + var visible = false; + var select = this.filesSelectElement; for (var i = 0; i < resource._scriptsPendingResourceLoad.length; ++i) { // Bind script to resource. var script = resource._scriptsPendingResourceLoad[i]; script.resource = resource; + if (select.options[select.selectedIndex] === script.filesSelectOption) + visible = true; + // Remove script from the files list. script.filesSelectOption.parentElement.removeChild(script.filesSelectOption); } // Adding first script will add resource. this._addScriptToFilesMenu(resource._scriptsPendingResourceLoad[0]); delete resource._scriptsPendingResourceLoad; + + if (visible) + this._showScriptOrResource(resource, { initialLoad: true }); + }, + + addConsoleMessage: function(message) + { + this._messages.push(message); + var sourceFrame = this._urlToSourceFrame[message.url]; + if (sourceFrame) + sourceFrame.addMessage(message); + }, + + clearConsoleMessages: function() + { + this._messages = []; + for (var url in this._urlToSourceFrame) + this._urlToSourceFrame[url].clearMessages(); }, selectedCallFrameId: function() @@ -316,7 +345,7 @@ WebInspector.ScriptsPanel.prototype = { return selectedCallFrame.id; }, - evaluateInSelectedCallFrame: function(code, updateInterface, objectGroup, callback) + evaluateInSelectedCallFrame: function(code, updateInterface, objectGroup, includeCommandLineAPI, callback) { var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; if (!this._paused || !selectedCallFrame) @@ -325,24 +354,15 @@ WebInspector.ScriptsPanel.prototype = { if (typeof updateInterface === "undefined") updateInterface = true; - var self = this; function updatingCallbackWrapper(result) { - callback(result); - if (updateInterface) - self.sidebarPanes.scopechain.update(selectedCallFrame); - } - this.doEvalInCallFrame(selectedCallFrame, code, objectGroup, updatingCallbackWrapper); - }, - - doEvalInCallFrame: function(callFrame, code, objectGroup, callback) - { - function evalCallback(result) - { - if (result) + if (result) { callback(WebInspector.RemoteObject.fromPayload(result)); + if (updateInterface) + this.sidebarPanes.scopechain.update(selectedCallFrame); + } } - InspectorBackend.evaluateOnCallFrame(callFrame.id, code, objectGroup, evalCallback); + InspectorBackend.evaluateOnCallFrame(selectedCallFrame.id, code, objectGroup, includeCommandLineAPI, updatingCallbackWrapper.bind(this)); }, _debuggerPaused: function(event) @@ -405,6 +425,8 @@ WebInspector.ScriptsPanel.prototype = { this._currentBackForwardIndex = -1; this._updateBackAndForwardButtons(); + this._urlToSourceFrame = {}; + this._messages = []; this._resourceForURLInFilesSelect = {}; this.filesSelectElement.removeChildren(); this.functionsSelectElement.removeChildren(); @@ -434,12 +456,6 @@ WebInspector.ScriptsPanel.prototype = { x.show(this.viewsContainerElement); }, - viewRecreated: function(oldView, newView) - { - if (this.visibleView === oldView) - this.visibleView = newView; - }, - canShowSourceLine: function(url, line) { if (!this._debuggerEnabled) @@ -484,43 +500,37 @@ WebInspector.ScriptsPanel.prototype = { this.sidebarPanes.callstack.handleShortcut(event); }, - scriptViewForScript: function(script) - { - if (!script) - return null; - if (!script._scriptView) - script._scriptView = new WebInspector.ScriptView(script); - return script._scriptView; - }, - - sourceFrameForScript: function(script) - { - var view = this.scriptViewForScript(script); - if (!view) - return null; - - // Setting up the source frame requires that we be attached. - if (!this.element.parentNode) - this.attach(); - - return view.sourceFrame; - }, - _sourceFrameForScriptOrResource: function(scriptOrResource) { if (scriptOrResource instanceof WebInspector.Resource) return this._sourceFrameForResource(scriptOrResource); - if (scriptOrResource instanceof WebInspector.Script) - return this.sourceFrameForScript(scriptOrResource); + return this._sourceFrameForScript(scriptOrResource); }, _sourceFrameForResource: function(resource) { - var view = WebInspector.ResourceView.resourceViewForResource(resource); - if (!view) - return null; + var sourceFrame = this._urlToSourceFrame[resource.url]; + if (sourceFrame) + return sourceFrame; + var contentProvider = new WebInspector.SourceFrameContentProviderForResource(resource); + var isScript = resource.type === WebInspector.Resource.Type.Script; + sourceFrame = new WebInspector.SourceFrame(contentProvider, resource.url, isScript); + for (var i = 0; i < this._messages.length; ++i) { + var message = this._messages[i]; + if (this._messages[i].url === resource.url) + sourceFrame.addMessage(message); + } + this._urlToSourceFrame[resource.url] = sourceFrame; + return sourceFrame; + }, - return view.sourceFrame; + _sourceFrameForScript: function(script) + { + if (script._sourceFrame) + return script._sourceFrame; + var contentProvider = new WebInspector.SourceFrameContentProviderForScript(script); + script._sourceFrame = new WebInspector.SourceFrame(contentProvider, script.sourceURL, true); + return script._sourceFrame; }, _showScriptOrResource: function(scriptOrResource, options) @@ -531,12 +541,7 @@ WebInspector.ScriptsPanel.prototype = { if (!scriptOrResource) return; - var view; - if (scriptOrResource instanceof WebInspector.Resource) - view = WebInspector.ResourceView.resourceViewForResource(scriptOrResource); - else if (scriptOrResource instanceof WebInspector.Script) - view = this.scriptViewForScript(scriptOrResource); - + var view = this._sourceFrameForScriptOrResource(scriptOrResource); if (!view) return; @@ -738,7 +743,7 @@ WebInspector.ScriptsPanel.prototype = { this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions."); else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions) this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions."); - + this._pauseOnExceptionButton.state = pauseOnExceptionsState; WebInspector.settings.pauseOnExceptionState = pauseOnExceptionsState; } @@ -824,8 +829,8 @@ WebInspector.ScriptsPanel.prototype = { _formatScript: function() { - if (this.visibleView && this.visibleView.sourceFrame) - this.visibleView.sourceFrame.formatSource(); + if (this.visibleView) + this.visibleView.formatSource(); }, _enableDebugging: function() @@ -841,10 +846,13 @@ WebInspector.ScriptsPanel.prototype = { this._waitingToPause = false; this._stepping = false; - if (this._debuggerEnabled) - InspectorBackend.disableDebugger(true); - else - InspectorBackend.enableDebugger(!!optionalAlways); + if (this._debuggerEnabled) { + WebInspector.settings.debuggerEnabled = false; + WebInspector.debuggerModel.disableDebugger(); + } else { + WebInspector.settings.debuggerEnabled = !!optionalAlways; + WebInspector.debuggerModel.enableDebugger(); + } }, _togglePauseOnExceptions: function() @@ -1043,3 +1051,41 @@ WebInspector.ScriptsPanel.prototype = { } WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype; + + +WebInspector.SourceFrameContentProviderForScript = function(script) +{ + WebInspector.SourceFrameContentProvider.call(this); + this._script = script; +} + +WebInspector.SourceFrameContentProviderForScript.prototype = { + requestContent: function(callback) + { + if (this._script.source) { + callback("text/javascript", this._script.source); + return; + } + + function didRequestSource(content) + { + var source; + if (content) { + var prefix = ""; + for (var i = 0; i < this._script.startingLine - 1; ++i) + prefix += "\n"; + source = prefix + content; + } else + source = WebInspector.UIString("<source is not available>"); + callback("text/javascript", source); + } + this._script.requestSource(didRequestSource.bind(this)); + }, + + scripts: function() + { + return [this._script]; + } +} + +WebInspector.SourceFrameContentProviderForScript.prototype.__proto__ = WebInspector.SourceFrameContentProvider.prototype; diff --git a/Source/WebCore/inspector/front-end/Settings.js b/Source/WebCore/inspector/front-end/Settings.js index e26b1d7..68b81a5 100644 --- a/Source/WebCore/inspector/front-end/Settings.js +++ b/Source/WebCore/inspector/front-end/Settings.js @@ -45,29 +45,33 @@ var Preferences = { onlineDetectionEnabled: true, nativeInstrumentationEnabled: false, resourceExportEnabled: false, - fileSystemEnabled: false, useDataURLForResourceImageIcons: true, showTimingTab: false, showCookiesTab: false, - debugMode: false + debugMode: false, + heapProfilerPresent: false, + detailedHeapProfiles: false } WebInspector.Settings = function() { this.installApplicationSetting("colorFormat", "hex"); this.installApplicationSetting("consoleHistory", []); + this.installApplicationSetting("debuggerEnabled", false); + this.installApplicationSetting("profilerEnabled", false); this.installApplicationSetting("eventListenersFilter", "all"); + this.installApplicationSetting("lastActivePanel", "elements"); this.installApplicationSetting("lastViewedScriptFile", "application"); + this.installApplicationSetting("monitoringXHREnabled", false); + this.installApplicationSetting("pauseOnExceptionState", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions); this.installApplicationSetting("resourcesLargeRows", true); this.installApplicationSetting("resourcesSortOptions", {timeOption: "responseTime", sizeOption: "transferSize"}); this.installApplicationSetting("resourceViewTab", "content"); this.installApplicationSetting("showInheritedComputedStyleProperties", false); this.installApplicationSetting("showUserAgentStyles", true); this.installApplicationSetting("watchExpressions", []); - this.installApplicationSetting("lastActivePanel", "elements"); - this.installApplicationSetting("pauseOnExceptionState", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions); + this.installApplicationSetting("breakpoints", []); - this.installProjectSetting("breakpoints", {}); this.installProjectSetting("nativeBreakpoints", []); } diff --git a/Source/WebCore/inspector/front-end/ShowMoreDataGridNode.js b/Source/WebCore/inspector/front-end/ShowMoreDataGridNode.js new file mode 100644 index 0000000..4fe2fef --- /dev/null +++ b/Source/WebCore/inspector/front-end/ShowMoreDataGridNode.js @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.ShowMoreDataGridNode = function(callback, nextCount, allCount) +{ + function populate(count) + { + var index = this.parent.children.indexOf(this); + this.parent.removeChild(this); + callback(count, index); + } + + this.showNext = document.createElement("button"); + this.showNext.setAttribute("type", "button"); + this.showNext.textContent = WebInspector.UIString("Show next %d", nextCount); + this.showNext.addEventListener("click", populate.bind(this, nextCount), false); + + if (allCount) { + this.showAll = document.createElement("button"); + this.showAll.setAttribute("type", "button"); + this.showAll.textContent = WebInspector.UIString("Show all %d", allCount); + this.showAll.addEventListener("click", populate.bind(this, allCount), false); + } + + WebInspector.DataGridNode.call(this, {summaryRow:true}, false); + this.selectable = false; +} + +WebInspector.ShowMoreDataGridNode.prototype = { + createCells: function() + { + var cell = document.createElement("td"); + if (this.depth) + cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px"); + cell.appendChild(this.showNext); + if (this.showAll) + cell.appendChild(this.showAll); + this._element.appendChild(cell); + + var columns = this.dataGrid.columns; + var count = 0; + for (var c in columns) + ++count; + while (--count > 0) { + cell = document.createElement("td"); + this._element.appendChild(cell); + } + } +}; + +WebInspector.ShowMoreDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; diff --git a/Source/WebCore/inspector/front-end/SidebarTreeElement.js b/Source/WebCore/inspector/front-end/SidebarTreeElement.js index c08b0ef..a27c457 100644 --- a/Source/WebCore/inspector/front-end/SidebarTreeElement.js +++ b/Source/WebCore/inspector/front-end/SidebarTreeElement.js @@ -164,8 +164,10 @@ WebInspector.SidebarTreeElement.prototype = { if (this.subtitleElement.textContent !== subtitle) this.subtitleElement.textContent = subtitle; this.titlesElement.removeStyleClass("no-subtitle"); - } else + } else { + this.subtitleElement.textContent = ""; this.titlesElement.addStyleClass("no-subtitle"); + } }, isEventWithinDisclosureTriangle: function(event) diff --git a/Source/WebCore/inspector/front-end/SourceFrame.js b/Source/WebCore/inspector/front-end/SourceFrame.js index eb89f24..f2e0be1 100644 --- a/Source/WebCore/inspector/front-end/SourceFrame.js +++ b/Source/WebCore/inspector/front-end/SourceFrame.js @@ -28,17 +28,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.SourceFrame = function(parentElement, contentProvider, url, isScript) +WebInspector.SourceFrame = function(contentProvider, url, isScript) { - this._parentElement = parentElement; + WebInspector.View.call(this); + + this.element.addStyleClass("script-view"); + this._contentProvider = contentProvider; this._url = url; this._isScript = isScript; - this._textModel = new WebInspector.TextEditorModel(); this._textModel.replaceTabsWithSpaces = true; + this._currentSearchResultIndex = -1; + this._searchResults = []; + this._messages = []; this._rowMessages = {}; this._messageBubbles = {}; @@ -48,28 +53,41 @@ WebInspector.SourceFrame = function(parentElement, contentProvider, url, isScrip WebInspector.SourceFrame.prototype = { - set visible(visible) + show: function(parentElement) { + WebInspector.View.prototype.show.call(this, parentElement); + if (!this._contentRequested) { this._contentRequested = true; this._contentProvider.requestContent(this._createTextViewer.bind(this)); } - if (visible) { - if (this._textViewer && this._scrollTop) - this._textViewer.element.scrollTop = this._scrollTop; - if (this._textViewer && this._scrollLeft) - this._textViewer.element.scrollLeft = this._scrollLeft; - if (this._textViewer) - this._textViewer.resize(); - } else { - this._hidePopup(); - if (this._textViewer) { - this._scrollTop = this._textViewer.element.scrollTop; - this._scrollLeft = this._textViewer.element.scrollLeft; - this._textViewer.freeCachedElements(); - } + if (this._textViewer) { + if (this._scrollTop) + this._textViewer.scrollTop = this._scrollTop; + if (this._scrollLeft) + this._textViewer.scrollLeft = this._scrollLeft; + this._textViewer.resize(); + } + }, + + hide: function() + { + if (this._textViewer) { + this._scrollTop = this._textViewer.scrollTop; + this._scrollLeft = this._textViewer.scrollLeft; + this._textViewer.freeCachedElements(); } + + WebInspector.View.prototype.hide.call(this); + + this._hidePopup(); + this._clearLineHighlight(); + }, + + hasContent: function() + { + return true; }, markDiff: function(diffData) @@ -95,7 +113,7 @@ WebInspector.SourceFrame.prototype = { // Don't add the message if there is no message or valid line or if the msg isn't an error or warning. if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning()) return; - this._messages.push(msg) + this._messages.push(msg); if (this._textViewer) this._addMessageToSource(msg); }, @@ -127,13 +145,14 @@ WebInspector.SourceFrame.prototype = { get scrollTop() { - return this._textViewer ? this._textViewer.element.scrollTop : 0; + return this._textViewer ? this._textViewer.scrollTop : this._scrollTop; }, set scrollTop(scrollTop) { + this._scrollTop = scrollTop; if (this._textViewer) - this._textViewer.element.scrollTop = scrollTop; + this._textViewer.scrollTop = scrollTop; }, highlightLine: function(line) @@ -144,7 +163,7 @@ WebInspector.SourceFrame.prototype = { this._lineToHighlight = line; }, - clearLineHighlight: function() + _clearLineHighlight: function() { if (this._textViewer) this._textViewer.clearLineHighlight(); @@ -152,11 +171,10 @@ WebInspector.SourceFrame.prototype = { delete this._lineToHighlight; }, - _createTextViewer: function(mimeType, content) + _createTextViewer: function(mimeType, text) { - this._content = content; - this._textModel.setText(null, content); - this._formatter = new WebInspector.ScriptFormatter(content); + this._content = new WebInspector.SourceFrameContent(text, this._contentProvider.scripts()); + this._textModel.setText(null, text); this._textViewer = new WebInspector.TextViewer(this._textModel, WebInspector.platform, this._url); var element = this._textViewer.element; @@ -165,7 +183,7 @@ WebInspector.SourceFrame.prototype = { element.addEventListener("mousemove", this._mouseMove.bind(this), true); element.addEventListener("scroll", this._scroll.bind(this), true); element.addEventListener("dblclick", this._doubleClick.bind(this), true); - this._parentElement.appendChild(element); + this.element.appendChild(element); this._textViewer.beginUpdates(); @@ -177,12 +195,6 @@ WebInspector.SourceFrame.prototype = { delete this._lineNumberToReveal; } - if (this._pendingMarkRange) { - var range = this._pendingMarkRange; - this.markAndRevealRange(range); - delete this._pendingMarkRange; - } - if (this._lineToHighlight) { this.highlightLine(this._lineToHighlight); delete this._lineToHighlight; @@ -196,9 +208,8 @@ WebInspector.SourceFrame.prototype = { this._textViewer.endUpdates(); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); - - if (this._canEditScripts) - this._textViewer.editCallback = this._editLine.bind(this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this); }, _setTextViewerDecorations: function() @@ -214,44 +225,108 @@ WebInspector.SourceFrame.prototype = { if (this._executionLine) this.setExecutionLine(this._executionLine); - var breakpoints = this._breakpoints(); - for (var i = 0; i < breakpoints.length; ++i) - this._addBreakpoint(breakpoints[i]); + this._breakpointIdToTextViewerLineNumber = {}; + this._textViewerLineNumberToBreakpointId = {}; + var breakpoints = WebInspector.debuggerModel.breakpoints; + for (var id in breakpoints) + this._breakpointAdded({ data: breakpoints[id] }); this._textViewer.resize(); this._textViewer.endUpdates(); }, - findSearchMatches: function(query, finishedCallback) + _shouldDisplayBreakpoint: function(breakpoint) { - function doFindSearchMatches() + if (this._url) + return this._url === breakpoint.url; + var scripts = this._contentProvider.scripts(); + for (var i = 0; i < scripts.length; ++i) { + if (breakpoint.sourceID === scripts[i].sourceID) + return true; + } + return false; + }, + + performSearch: function(query, callback) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + function doFindSearchMatches(query) { - var ranges = []; + this._currentSearchResultIndex = -1; + this._searchResults = []; // First do case-insensitive search. var regexObject = createSearchRegex(query); - this._collectRegexMatches(regexObject, ranges); + this._collectRegexMatches(regexObject, this._searchResults); // Then try regex search if user knows the / / hint. try { if (/^\/.*\/$/.test(query)) - this._collectRegexMatches(new RegExp(query.substring(1, query.length - 1)), ranges); + this._collectRegexMatches(new RegExp(query.substring(1, query.length - 1)), this._searchResults); } catch (e) { // Silent catch. } - finishedCallback(ranges); + + callback(this, this._searchResults.length); } if (this._textViewer) - doFindSearchMatches.call(this); + doFindSearchMatches.call(this, query); else - this._delayedFindSearchMatches = doFindSearchMatches.bind(this); + this._delayedFindSearchMatches = doFindSearchMatches.bind(this, query); + }, - cancelFindSearchMatches: function() + searchCanceled: function() { delete this._delayedFindSearchMatches; + if (!this._textViewer) + return; + + this._currentSearchResultIndex = -1; + this._searchResults = []; + this._textViewer.markAndRevealRange(null); + }, + + jumpToFirstSearchResult: function() + { + this._jumpToSearchResult(0); + }, + + jumpToLastSearchResult: function() + { + this._jumpToSearchResult(this._searchResults.length - 1); + }, + + jumpToNextSearchResult: function() + { + this._jumpToSearchResult(this._currentSearchResultIndex + 1); + }, + + jumpToPreviousSearchResult: function() + { + this._jumpToSearchResult(this._currentSearchResultIndex - 1); + }, + + showingFirstSearchResult: function() + { + return this._searchResults.length && this._currentSearchResultIndex === 0; + }, + + showingLastSearchResult: function() + { + return this._searchResults.length && this._currentSearchResultIndex === (this._searchResults.length - 1); + }, + + _jumpToSearchResult: function(index) + { + if (!this._textViewer || !this._searchResults.length) + return; + this._currentSearchResultIndex = (index + this._searchResults.length) % this._searchResults.length; + this._textViewer.markAndRevealRange(this._searchResults[this._currentSearchResultIndex]); }, _collectRegexMatches: function(regexObject, ranges) @@ -271,22 +346,6 @@ WebInspector.SourceFrame.prototype = { return ranges; }, - markAndRevealRange: function(range) - { - if (this._textViewer) - this._textViewer.markAndRevealRange(range); - else - this._pendingMarkRange = range; - }, - - clearMarkedRange: function() - { - if (this._textViewer) { - this._textViewer.markAndRevealRange(null); - } else - delete this._pendingMarkRange; - }, - _incrementMessageRepeatCount: function(msg, repeatDelta) { if (!msg._resourceMessageLineElement) @@ -307,7 +366,7 @@ WebInspector.SourceFrame.prototype = { this._executionLine = lineNumber; if (!this._textViewer) return; - var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(this._executionLine - 1); + var textViewerLineNumber = this._originalLocationToTextViewerLineNumber(this._executionLine - 1, 0); this._textViewer.addDecoration(textViewerLineNumber, "webkit-execution-line"); }, @@ -315,7 +374,7 @@ WebInspector.SourceFrame.prototype = { { if (!this._textViewer) return; - var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(this._executionLine - 1); + var textViewerLineNumber = this._originalLocationToTextViewerLineNumber(this._executionLine - 1, 0); this._textViewer.removeDecoration(textViewerLineNumber, "webkit-execution-line"); delete this._executionLine; }, @@ -356,7 +415,7 @@ WebInspector.SourceFrame.prototype = { _addMessageToSource: function(msg) { - if (msg.line >= this._textModel.linesCount) + if (msg.line > this._textModel.linesCount) return; var messageBubbleElement = this._messageBubbles[msg.line]; @@ -412,54 +471,55 @@ WebInspector.SourceFrame.prototype = { { var breakpoint = event.data; - if (breakpoint.sourceID in this._sourceIDSet()) - this._addBreakpoint(breakpoint); - }, + if (!this._shouldDisplayBreakpoint(breakpoint)) + return; - _addBreakpoint: function(breakpoint) - { - var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1); + var resolved = breakpoint.locations.length; + var location = resolved ? breakpoint.locations[0] : breakpoint; + + var textViewerLineNumber = this._originalLocationToTextViewerLineNumber(location.lineNumber, location.columnNumber); if (textViewerLineNumber >= this._textModel.linesCount) return; - breakpoint.addEventListener("enable-changed", this._breakpointChanged, this); - breakpoint.addEventListener("condition-changed", this._breakpointChanged, this); - breakpoint.addEventListener("removed", this._breakpointRemoved, this); + var existingBreakpointId = this._textViewerLineNumberToBreakpointId[textViewerLineNumber]; + if (existingBreakpointId) { + WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); + return; + } - this._setBreakpointDecoration(textViewerLineNumber, breakpoint.enabled, !!breakpoint.condition); + this._breakpointIdToTextViewerLineNumber[breakpoint.id] = textViewerLineNumber; + this._textViewerLineNumberToBreakpointId[textViewerLineNumber] = breakpoint.id; + this._setBreakpointDecoration(textViewerLineNumber, resolved, breakpoint.enabled, !!breakpoint.condition); }, _breakpointRemoved: function(event) { - var breakpoint = event.target; + var breakpointId = event.data; - breakpoint.removeEventListener("enable-changed", null, this); - breakpoint.removeEventListener("condition-changed", null, this); - breakpoint.removeEventListener("removed", null, this); + var textViewerLineNumber = this._breakpointIdToTextViewerLineNumber[breakpointId]; + if (textViewerLineNumber === undefined) + return; - var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1); + delete this._breakpointIdToTextViewerLineNumber[breakpointId]; + delete this._textViewerLineNumberToBreakpointId[textViewerLineNumber]; this._removeBreakpointDecoration(textViewerLineNumber); }, - _breakpointChanged: function(event) + _breakpointResolved: function(event) { - var breakpoint = event.target; - var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1); - this._setBreakpointDecoration(textViewerLineNumber, breakpoint.enabled, !!breakpoint.condition); + var breakpoint = event.data; + this._breakpointRemoved({ data: breakpoint.id }); + this._breakpointAdded({ data: breakpoint }); }, - _setBreakpointDecoration: function(lineNumber, enabled, hasCondition) + _setBreakpointDecoration: function(lineNumber, resolved, enabled, hasCondition) { this._textViewer.beginUpdates(); this._textViewer.addDecoration(lineNumber, "webkit-breakpoint"); - if (enabled) - this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled"); - else + if (!enabled) this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled"); if (hasCondition) this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional"); - else - this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional"); this._textViewer.endUpdates(); }, @@ -480,49 +540,49 @@ WebInspector.SourceFrame.prototype = { var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); if (!target) return; - var textViewerLineNumber = target.parentElement.lineNumber; - var originalLineNumber = this._formatter.formattedLineNumberToOriginalLineNumber(textViewerLineNumber); + var textViewerLineNumber = target.lineNumber; var contextMenu = new WebInspector.ContextMenu(); - contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToLine.bind(this, originalLineNumber)); + contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToLine.bind(this, textViewerLineNumber)); - var breakpoint = this._findBreakpoint(originalLineNumber); + var breakpoint = this._findBreakpoint(textViewerLineNumber); if (!breakpoint) { // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint. - contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, originalLineNumber, "", true)); + contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, textViewerLineNumber, "", true)); function addConditionalBreakpoint() { - this._setBreakpointDecoration(textViewerLineNumber, true, true); + this._setBreakpointDecoration(textViewerLineNumber, true, true, true); function didEditBreakpointCondition(committed, condition) { this._removeBreakpointDecoration(textViewerLineNumber); if (committed) - this._setBreakpoint(originalLineNumber, true, condition); + this._setBreakpoint(textViewerLineNumber, condition, true); } this._editBreakpointCondition(textViewerLineNumber, "", didEditBreakpointCondition.bind(this)); } contextMenu.appendItem(WebInspector.UIString("Add Conditional Breakpoint…"), addConditionalBreakpoint.bind(this)); } else { // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable. - contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), breakpoint.remove.bind(breakpoint)); + function removeBreakpoint() + { + WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); + } + contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), removeBreakpoint); function editBreakpointCondition() { function didEditBreakpointCondition(committed, condition) { - if (committed) { - breakpoint.remove(); - this._setBreakpoint(originalLineNumber, breakpoint.enabled, condition); - } + if (committed) + WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, condition, breakpoint.enabled); } this._editBreakpointCondition(textViewerLineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this)); } contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpointCondition.bind(this)); function setBreakpointEnabled(enabled) { - breakpoint.remove(); - this._setBreakpoint(originalLineNumber, enabled, breakpoint.condition); + WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, breakpoint.condition, enabled); } if (breakpoint.enabled) contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), setBreakpointEnabled.bind(this, false)); @@ -546,15 +606,16 @@ WebInspector.SourceFrame.prototype = { var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); if (!target) return; - var originalLineNumber = this._formatter.formattedLineNumberToOriginalLineNumber(target.parentElement.lineNumber); + var textViewerLineNumber = target.lineNumber; - var breakpoint = this._findBreakpoint(originalLineNumber); + var breakpoint = this._findBreakpoint(textViewerLineNumber); if (breakpoint) { - breakpoint.remove(); if (event.shiftKey) - this._setBreakpoint(originalLineNumber, !breakpoint.enabled, breakpoint.condition); + WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, breakpoint.condition, !breakpoint.enabled); + else + WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); } else - this._setBreakpoint(originalLineNumber, true, ""); + this._setBreakpoint(textViewerLineNumber, "", true); event.preventDefault(); }, @@ -629,7 +690,7 @@ WebInspector.SourceFrame.prototype = { if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused) return; - var lineRow = element.enclosingNodeOrSelfWithNodeName("tr"); + var lineRow = element.enclosingNodeOrSelfWithClass("webkit-line-content"); if (!lineRow) return; @@ -713,7 +774,7 @@ WebInspector.SourceFrame.prototype = { return; showObjectPopup.call(this, result); } - WebInspector.panels.scripts.evaluateInSelectedCallFrame(element.textContent, false, this._popoverObjectGroup, evaluateCallback.bind(this)); + WebInspector.panels.scripts.evaluateInSelectedCallFrame(element.textContent, false, this._popoverObjectGroup, false, evaluateCallback.bind(this)); }, _editBreakpointCondition: function(lineNumber, condition, callback) @@ -752,7 +813,7 @@ WebInspector.SourceFrame.prototype = { var editorElement = document.createElement("input"); editorElement.id = "source-frame-breakpoint-condition"; editorElement.className = "monospace"; - editorElement.type = "text" + editorElement.type = "text"; conditionElement.appendChild(editorElement); this._conditionEditorElement = editorElement; @@ -785,23 +846,24 @@ WebInspector.SourceFrame.prototype = { formatSource: function() { - if (!this._formatter) + if (!this._content) return; - function didFormat(source) + function didFormat(formattedContent) { - this._textModel.setText(null, source); + this._formattedContent = formattedContent; + this._textModel.setText(null, formattedContent.text); this._setTextViewerDecorations(); } - this._formatter.format(didFormat.bind(this)); + var formatter = new WebInspector.ScriptFormatter(); + formatter.formatContent(this._content, didFormat.bind(this)) }, _continueToLine: function(lineNumber) { - var sourceID = this._sourceIDForLine(lineNumber); - if (!sourceID) - return; - WebInspector.debuggerModel.continueToLine(sourceID, lineNumber + 1); + var location = this._textViewerLineNumberToScriptLocation(lineNumber); + if (location.sourceID) + WebInspector.debuggerModel.continueToLine(location.sourceID, location.lineNumber); }, _doubleClick: function(event) @@ -809,79 +871,66 @@ WebInspector.SourceFrame.prototype = { if (!Preferences.canEditScriptSource || !this._isScript) return; - var target = event.target.enclosingNodeOrSelfWithNodeName("TD"); - if (!target || target.parentElement.firstChild === target) + var lineRow = event.target.enclosingNodeOrSelfWithClass("webkit-line-content"); + if (!lineRow) return; // Do not trigger editing from line numbers. - var lineRow = target.parentElement; var lineNumber = lineRow.lineNumber; - var sourceID = this._sourceIDForLine(lineNumber); - if (!sourceID) + var location = this._textViewerLineNumberToScriptLocation(lineNumber); + if (!location.sourceID) return; function didEditLine(newContent) { var lines = []; - var oldLines = this._content.split('\n'); + var oldLines = this._content.text.split('\n'); for (var i = 0; i < oldLines.length; ++i) { if (i === lineNumber) lines.push(newContent); else lines.push(oldLines[i]); } - WebInspector.debuggerModel.editScriptSource(sourceID, lines.join("\n")); + WebInspector.debuggerModel.editScriptSource(location.sourceID, lines.join("\n")); } this._textViewer.editLine(lineRow, didEditLine.bind(this)); }, - _setBreakpoint: function(lineNumber, enabled, condition) + _setBreakpoint: function(lineNumber, condition, enabled) { - var sourceID = this._sourceIDForLine(lineNumber); - if (!sourceID) + var location = this._textViewerLineNumberToScriptLocation(lineNumber); + if (this._url) + WebInspector.debuggerModel.setBreakpoint(this._url, location.lineNumber, location.columnNumber, condition, enabled); + else if (location.sourceID) + WebInspector.debuggerModel.setBreakpointBySourceId(location.sourceID, location.lineNumber, location.columnNumber, condition, enabled); + else return; - WebInspector.debuggerModel.setBreakpoint(sourceID, lineNumber + 1, enabled, condition); + if (!WebInspector.panels.scripts.breakpointsActivated) WebInspector.panels.scripts.toggleBreakpointsClicked(); }, - _breakpoints: function() + _findBreakpoint: function(textViewerLineNumber) { - var sourceIDSet = this._sourceIDSet(); - return WebInspector.debuggerModel.queryBreakpoints(function(b) { return b.sourceID in sourceIDSet; }); + var breakpointId = this._textViewerLineNumberToBreakpointId[textViewerLineNumber]; + return WebInspector.debuggerModel.breakpointForId(breakpointId); }, - _findBreakpoint: function(lineNumber) + _originalLocationToTextViewerLineNumber: function(lineNumber, columnNumber) { - var sourceID = this._sourceIDForLine(lineNumber); - return WebInspector.debuggerModel.findBreakpoint(sourceID, lineNumber + 1); + if (!this._formattedContent) + return lineNumber; + return this._formattedContent.originalLocationToFormattedLocation(lineNumber, columnNumber).lineNumber; }, - _sourceIDForLine: function(lineNumber) + _textViewerLineNumberToScriptLocation: function(lineNumber) { - var sourceIDForLine = null; - var closestStartingLine = 0; - var scripts = this._contentProvider.scripts(); - for (var i = 0; i < scripts.length; ++i) { - var lineOffset = scripts[i].lineOffset; - if (lineOffset <= lineNumber && lineOffset >= closestStartingLine) { - closestStartingLine = lineOffset; - sourceIDForLine = scripts[i].sourceID; - } - } - return sourceIDForLine; - }, - - _sourceIDSet: function() - { - var scripts = this._contentProvider.scripts(); - var sourceIDSet = {}; - for (var i = 0; i < scripts.length; ++i) - sourceIDSet[scripts[i].sourceID] = true; - return sourceIDSet; + if (!this._formattedContent) + return this._content.scriptLocationForLineNumber(lineNumber); + return this._formattedContent.scriptLocationForFormattedLineNumber(lineNumber); } } -WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype; +WebInspector.SourceFrame.prototype.__proto__ = WebInspector.View.prototype; WebInspector.SourceFrameContentProvider = function() diff --git a/Source/WebCore/inspector/front-end/SourceFrameContent.js b/Source/WebCore/inspector/front-end/SourceFrameContent.js new file mode 100644 index 0000000..e4a74ec --- /dev/null +++ b/Source/WebCore/inspector/front-end/SourceFrameContent.js @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.SourceFrameContent = function(text, scripts) +{ + if (scripts.length && scripts[0].length < text.length) { + // WebKit html lexer normalizes line endings and scripts are passed to VM with "\n" line endings. + // However, resource content has original line endings, so we have to normalize line endings here. + text = text.replace(/\r\n/g, "\n"); + } + this._text = text; + this._lineEndings = text.findAll("\n"); + this._lineEndings.push(text.length); + + this._scriptRanges = []; + for (var i = 0; i < scripts.length; ++i) { + var script = scripts[i]; + var offset = this.locationToPosition(script.lineOffset, script.columnOffset); + this._scriptRanges.push({ start: offset, end: offset + script.length, script: script }); + } + this._scriptRanges.sort(function(x, y) { return x.start - y.start; }); +} + +WebInspector.SourceFrameContent.prototype = { + get text() + { + return this._text; + }, + + get scriptRanges() + { + return this._scriptRanges; + }, + + locationToPosition: function(lineNumber, columnNumber) + { + var position = lineNumber ? this._lineEndings[lineNumber - 1] + 1 : 0; + return position + columnNumber; + }, + + positionToLocation: function(position) + { + var location = {}; + location.lineNumber = this._lineEndings.upperBound(position - 1); + if (!location.lineNumber) + location.columnNumber = position; + else + location.columnNumber = position - this._lineEndings[location.lineNumber - 1] - 1; + return location; + }, + + scriptLocationForLineNumber: function(lineNumber) + { + var range = this.lineNumberToRange(lineNumber); + return this.scriptLocationForRange(range.start, range.end); + }, + + scriptLocationForRange: function(start, end) + { + var position = start; + var scriptRange = this._intersectingScriptRange(start, end); + if (scriptRange) + position = Math.max(position, scriptRange.start); + var scriptLocation = this.positionToLocation(position); + if (scriptRange) + scriptLocation.sourceID = scriptRange.script.sourceID; + return scriptLocation; + }, + + lineNumberToRange: function(lineNumber) + { + var previousLineEnd = this._lineEndings[lineNumber - 1] || 0; + var lineEnd = this._lineEndings[lineNumber]; + return { start: previousLineEnd + 1, end: lineEnd }; + }, + + _intersectingScriptRange: function(start, end) + { + for (var i = 0; i < this._scriptRanges.length; ++i) { + var scriptRange = this._scriptRanges[i]; + if (start < scriptRange.end && end > scriptRange.start) + return scriptRange; + } + } +} + + +WebInspector.FormattedSourceFrameContent = function(originalContent, text, mapping) +{ + this._originalContent = originalContent; + this._formattedContent = new WebInspector.SourceFrameContent(text, []); + this._mapping = mapping; +} + +WebInspector.FormattedSourceFrameContent.prototype = { + get text() + { + return this._formattedContent.text; + }, + + originalLocationToFormattedLocation: function(lineNumber, columnNumber) + { + var originalPosition = this._originalContent.locationToPosition(lineNumber, columnNumber); + var formattedPosition = this._convertPosition(this._mapping.original, this._mapping.formatted, originalPosition); + return this._formattedContent.positionToLocation(formattedPosition); + }, + + scriptLocationForFormattedLineNumber: function(lineNumber) + { + var range = this._formattedContent.lineNumberToRange(lineNumber); + var start = this._convertPosition(this._mapping.formatted, this._mapping.original, range.start); + var end = this._convertPosition(this._mapping.formatted, this._mapping.original, range.end); + return this._originalContent.scriptLocationForRange(start, end); + }, + + _convertPosition: function(positions1, positions2, position) + { + var index = positions1.upperBound(position); + var range1 = positions1[index] - positions1[index - 1]; + var range2 = positions2[index] - positions2[index - 1]; + var position2 = positions2[index - 1]; + if (range1) + position2 += Math.round((position - positions1[index - 1]) * range2 / range1); + return position2; + } +} diff --git a/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.js b/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.js index cfbc44f..48c5bd4 100644 --- a/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.js +++ b/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.js @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 on Thu Feb 25 21:44:55 2010 */ +/* Generated by re2c 0.13.5 on Fri Jan 28 18:32:27 2011 */ /* * Copyright (C) 2009 Google Inc. All rights reserved. * @@ -67,7 +67,8 @@ WebInspector.SourceHTMLTokenizer = function() ATTRIBUTE_VALUE: 2, LINKIFY: 4, A_NODE: 8, - SCRIPT: 16 + SCRIPT: 16, + STYLE: 32 }; this.initialCondition = { lexCondition: this._lexConditions.INITIAL, parseCondition: this._parseConditions.INITIAL }; @@ -82,6 +83,12 @@ WebInspector.SourceHTMLTokenizer.prototype = { this._internalJavaScriptTokenizer.line = line.substring(0, match.index); } else this._internalJavaScriptTokenizer.line = line; + } else if (this._internalCSSTokenizer) { + var match = /<\/style/i.exec(line); + if (match) { + this._internalCSSTokenizer.line = line.substring(0, match.index); + } else + this._internalCSSTokenizer.line = line; } this._line = line; }, @@ -146,6 +153,18 @@ WebInspector.SourceHTMLTokenizer.prototype = { return result; } else if (cursor !== this._line.length) delete this._internalJavaScriptTokenizer; + } else if (this._internalCSSTokenizer) { + // Re-set line to force </style> detection first. + this.line = this._line; + if (cursor !== this._internalCSSTokenizer._line.length) { + // Tokenizer is stateless, so restore its condition before tokenizing and save it after. + this._internalCSSTokenizer.condition = this._condition.internalCSSTokenizerCondition; + var result = this._internalCSSTokenizer.nextToken(cursor); + this.tokenType = this._internalCSSTokenizer.tokenType; + this._condition.internalCSSTokenizerCondition = this._internalCSSTokenizer.condition; + return result; + } else if (cursor !== this._line.length) + delete this._internalCSSTokenizer; } var cursorOnEnter = cursor; @@ -331,8 +350,8 @@ case 39: case 40: this.setLexCondition(this._lexConditions.TAG); { - if (this._condition.parseCondition & this._parseConditions.SCRIPT) { - // Do not tokenize script tag contents, keep lexer state although processing "<". + if (this._condition.parseCondition & (this._parseConditions.SCRIPT | this._parseConditions.STYLE)) { + // Do not tokenize script and style tag contents, keep lexer state, even though processing "<". this.setLexCondition(this._lexConditions.INITIAL); this.tokenType = null; return cursor; @@ -345,13 +364,21 @@ case 40: case 41: yyaccept = 0; yych = this._charAt(YYMARKER = ++cursor); - if (yych == 'S') { gotoCase = 68; continue; }; - if (yych == 's') { gotoCase = 68; continue; }; + if (yych == 'S') { gotoCase = 73; continue; }; + if (yych == 's') { gotoCase = 73; continue; }; { gotoCase = 40; continue; }; case 42: yych = this._charAt(++cursor); - if (yych == 'C') { gotoCase = 62; continue; }; - if (yych == 'c') { gotoCase = 62; continue; }; + if (yych <= 'T') { + if (yych == 'C') { gotoCase = 62; continue; }; + if (yych >= 'T') { gotoCase = 63; continue; }; + } else { + if (yych <= 'c') { + if (yych >= 'c') { gotoCase = 62; continue; }; + } else { + if (yych == 't') { gotoCase = 63; continue; }; + } + } case 43: cursor = YYMARKER; { gotoCase = 40; continue; }; @@ -421,56 +448,113 @@ case 59: { this.tokenType = "html-comment"; return cursor; } case 62: yych = this._charAt(++cursor); - if (yych == 'R') { gotoCase = 63; continue; }; - if (yych != 'r') { gotoCase = 43; continue; }; + if (yych == 'R') { gotoCase = 68; continue; }; + if (yych == 'r') { gotoCase = 68; continue; }; + { gotoCase = 43; continue; }; case 63: yych = this._charAt(++cursor); - if (yych == 'I') { gotoCase = 64; continue; }; - if (yych != 'i') { gotoCase = 43; continue; }; + if (yych == 'Y') { gotoCase = 64; continue; }; + if (yych != 'y') { gotoCase = 43; continue; }; case 64: yych = this._charAt(++cursor); - if (yych == 'P') { gotoCase = 65; continue; }; - if (yych != 'p') { gotoCase = 43; continue; }; + if (yych == 'L') { gotoCase = 65; continue; }; + if (yych != 'l') { gotoCase = 43; continue; }; case 65: yych = this._charAt(++cursor); - if (yych == 'T') { gotoCase = 66; continue; }; - if (yych != 't') { gotoCase = 43; continue; }; + if (yych == 'E') { gotoCase = 66; continue; }; + if (yych != 'e') { gotoCase = 43; continue; }; case 66: ++cursor; this.setLexCondition(this._lexConditions.TAG); { - if (this._condition.parseCondition & this._parseConditions.SCRIPT) { - // Do not tokenize script tag contents, keep lexer state although processing "<". + if (this._condition.parseCondition & this._parseConditions.STYLE) { + // Do not tokenize style tag contents, keep lexer state, even though processing "<". this.setLexCondition(this._lexConditions.INITIAL); this.tokenType = null; return cursor; } this.tokenType = "html-tag"; - this._condition.parseCondition = this._parseConditions.SCRIPT; + this._condition.parseCondition = this._parseConditions.STYLE; this._setExpectingAttribute(); return cursor; } case 68: yych = this._charAt(++cursor); - if (yych == 'C') { gotoCase = 69; continue; }; - if (yych != 'c') { gotoCase = 43; continue; }; + if (yych == 'I') { gotoCase = 69; continue; }; + if (yych != 'i') { gotoCase = 43; continue; }; case 69: yych = this._charAt(++cursor); - if (yych == 'R') { gotoCase = 70; continue; }; - if (yych != 'r') { gotoCase = 43; continue; }; + if (yych == 'P') { gotoCase = 70; continue; }; + if (yych != 'p') { gotoCase = 43; continue; }; case 70: yych = this._charAt(++cursor); - if (yych == 'I') { gotoCase = 71; continue; }; - if (yych != 'i') { gotoCase = 43; continue; }; + if (yych == 'T') { gotoCase = 71; continue; }; + if (yych != 't') { gotoCase = 43; continue; }; case 71: + ++cursor; + this.setLexCondition(this._lexConditions.TAG); + { + if (this._condition.parseCondition & this._parseConditions.SCRIPT) { + // Do not tokenize script tag contents, keep lexer state, even though processing "<". + this.setLexCondition(this._lexConditions.INITIAL); + this.tokenType = null; + return cursor; + } + this.tokenType = "html-tag"; + this._condition.parseCondition = this._parseConditions.SCRIPT; + this._setExpectingAttribute(); + return cursor; + } +case 73: + yych = this._charAt(++cursor); + if (yych <= 'T') { + if (yych == 'C') { gotoCase = 75; continue; }; + if (yych <= 'S') { gotoCase = 43; continue; }; + } else { + if (yych <= 'c') { + if (yych <= 'b') { gotoCase = 43; continue; }; + { gotoCase = 75; continue; }; + } else { + if (yych != 't') { gotoCase = 43; continue; }; + } + } + yych = this._charAt(++cursor); + if (yych == 'Y') { gotoCase = 81; continue; }; + if (yych == 'y') { gotoCase = 81; continue; }; + { gotoCase = 43; continue; }; +case 75: + yych = this._charAt(++cursor); + if (yych == 'R') { gotoCase = 76; continue; }; + if (yych != 'r') { gotoCase = 43; continue; }; +case 76: + yych = this._charAt(++cursor); + if (yych == 'I') { gotoCase = 77; continue; }; + if (yych != 'i') { gotoCase = 43; continue; }; +case 77: yych = this._charAt(++cursor); - if (yych == 'P') { gotoCase = 72; continue; }; + if (yych == 'P') { gotoCase = 78; continue; }; if (yych != 'p') { gotoCase = 43; continue; }; -case 72: +case 78: yych = this._charAt(++cursor); - if (yych == 'T') { gotoCase = 73; continue; }; + if (yych == 'T') { gotoCase = 79; continue; }; if (yych != 't') { gotoCase = 43; continue; }; -case 73: +case 79: + ++cursor; + this.setLexCondition(this._lexConditions.TAG); + { + this.tokenType = "html-tag"; + this._condition.parseCondition = this._parseConditions.INITIAL; + return cursor; + } +case 81: + yych = this._charAt(++cursor); + if (yych == 'L') { gotoCase = 82; continue; }; + if (yych != 'l') { gotoCase = 43; continue; }; +case 82: + yych = this._charAt(++cursor); + if (yych == 'E') { gotoCase = 83; continue; }; + if (yych != 'e') { gotoCase = 43; continue; }; +case 83: ++cursor; this.setLexCondition(this._lexConditions.TAG); { @@ -482,78 +566,78 @@ case 73: case this.case_SSTRING: yych = this._charAt(cursor); if (yych <= '\f') { - if (yych == '\n') { gotoCase = 79; continue; }; - { gotoCase = 78; continue; }; + if (yych == '\n') { gotoCase = 89; continue; }; + { gotoCase = 88; continue; }; } else { - if (yych <= '\r') { gotoCase = 79; continue; }; - if (yych == '\'') { gotoCase = 81; continue; }; - { gotoCase = 78; continue; }; + if (yych <= '\r') { gotoCase = 89; continue; }; + if (yych == '\'') { gotoCase = 91; continue; }; + { gotoCase = 88; continue; }; } -case 77: +case 87: { return this._stringToken(cursor); } -case 78: +case 88: yych = this._charAt(++cursor); - { gotoCase = 85; continue; }; -case 79: + { gotoCase = 95; continue; }; +case 89: ++cursor; { this.tokenType = null; return cursor; } -case 81: +case 91: ++cursor; -case 82: +case 92: this.setLexCondition(this._lexConditions.TAG); { return this._stringToken(cursor, true); } -case 83: +case 93: yych = this._charAt(++cursor); - { gotoCase = 82; continue; }; -case 84: + { gotoCase = 92; continue; }; +case 94: ++cursor; yych = this._charAt(cursor); -case 85: +case 95: if (yych <= '\f') { - if (yych == '\n') { gotoCase = 77; continue; }; - { gotoCase = 84; continue; }; + if (yych == '\n') { gotoCase = 87; continue; }; + { gotoCase = 94; continue; }; } else { - if (yych <= '\r') { gotoCase = 77; continue; }; - if (yych == '\'') { gotoCase = 83; continue; }; - { gotoCase = 84; continue; }; + if (yych <= '\r') { gotoCase = 87; continue; }; + if (yych == '\'') { gotoCase = 93; continue; }; + { gotoCase = 94; continue; }; } /* *********************************** */ case this.case_TAG: yych = this._charAt(cursor); if (yych <= '&') { if (yych <= '\r') { - if (yych == '\n') { gotoCase = 90; continue; }; - if (yych >= '\r') { gotoCase = 90; continue; }; + if (yych == '\n') { gotoCase = 100; continue; }; + if (yych >= '\r') { gotoCase = 100; continue; }; } else { if (yych <= ' ') { - if (yych >= ' ') { gotoCase = 90; continue; }; + if (yych >= ' ') { gotoCase = 100; continue; }; } else { - if (yych == '"') { gotoCase = 92; continue; }; + if (yych == '"') { gotoCase = 102; continue; }; } } } else { if (yych <= '>') { if (yych <= ';') { - if (yych <= '\'') { gotoCase = 93; continue; }; + if (yych <= '\'') { gotoCase = 103; continue; }; } else { - if (yych <= '<') { gotoCase = 90; continue; }; - if (yych <= '=') { gotoCase = 94; continue; }; - { gotoCase = 96; continue; }; + if (yych <= '<') { gotoCase = 100; continue; }; + if (yych <= '=') { gotoCase = 104; continue; }; + { gotoCase = 106; continue; }; } } else { if (yych <= '[') { - if (yych >= '[') { gotoCase = 90; continue; }; + if (yych >= '[') { gotoCase = 100; continue; }; } else { - if (yych == ']') { gotoCase = 90; continue; }; + if (yych == ']') { gotoCase = 100; continue; }; } } } ++cursor; yych = this._charAt(cursor); - { gotoCase = 109; continue; }; -case 89: + { gotoCase = 119; continue; }; +case 99: { - if (this._condition.parseCondition === this._parseConditions.SCRIPT) { + if (this._condition.parseCondition === this._parseConditions.SCRIPT || this._condition.parseCondition === this._parseConditions.STYLE) { // Fall through if expecting attributes. this.tokenType = null; return cursor; @@ -580,18 +664,18 @@ case 89: this.tokenType = null; return cursor; } -case 90: +case 100: ++cursor; { this.tokenType = null; return cursor; } -case 92: +case 102: yyaccept = 0; yych = this._charAt(YYMARKER = ++cursor); - { gotoCase = 105; continue; }; -case 93: + { gotoCase = 115; continue; }; +case 103: yyaccept = 0; yych = this._charAt(YYMARKER = ++cursor); - { gotoCase = 99; continue; }; -case 94: + { gotoCase = 109; continue; }; +case 104: ++cursor; { if (this._isExpectingAttribute()) @@ -599,7 +683,7 @@ case 94: this.tokenType = null; return cursor; } -case 96: +case 106: ++cursor; this.setLexCondition(this._lexConditions.INITIAL); { @@ -613,68 +697,77 @@ case 96: return cursor; } + if (this._condition.parseCondition & this._parseConditions.STYLE) { + if (!this._internalCSSTokenizer) { + this._internalCSSTokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/css"); + this._condition.internalCSSTokenizerCondition = this._internalCSSTokenizer.initialCondition; + } + // Do not tokenize style tag contents. + return cursor; + } + this._condition.parseCondition = this._parseConditions.INITIAL; return cursor; } -case 98: +case 108: ++cursor; yych = this._charAt(cursor); -case 99: +case 109: if (yych <= '\f') { - if (yych != '\n') { gotoCase = 98; continue; }; + if (yych != '\n') { gotoCase = 108; continue; }; } else { - if (yych <= '\r') { gotoCase = 100; continue; }; - if (yych == '\'') { gotoCase = 102; continue; }; - { gotoCase = 98; continue; }; + if (yych <= '\r') { gotoCase = 110; continue; }; + if (yych == '\'') { gotoCase = 112; continue; }; + { gotoCase = 108; continue; }; } -case 100: +case 110: ++cursor; this.setLexCondition(this._lexConditions.SSTRING); { return this._stringToken(cursor); } -case 102: +case 112: ++cursor; { return this._stringToken(cursor, true); } -case 104: +case 114: ++cursor; yych = this._charAt(cursor); -case 105: +case 115: if (yych <= '\f') { - if (yych != '\n') { gotoCase = 104; continue; }; + if (yych != '\n') { gotoCase = 114; continue; }; } else { - if (yych <= '\r') { gotoCase = 106; continue; }; - if (yych == '"') { gotoCase = 102; continue; }; - { gotoCase = 104; continue; }; + if (yych <= '\r') { gotoCase = 116; continue; }; + if (yych == '"') { gotoCase = 112; continue; }; + { gotoCase = 114; continue; }; } -case 106: +case 116: ++cursor; this.setLexCondition(this._lexConditions.DSTRING); { return this._stringToken(cursor); } -case 108: +case 118: ++cursor; yych = this._charAt(cursor); -case 109: +case 119: if (yych <= '"') { if (yych <= '\r') { - if (yych == '\n') { gotoCase = 89; continue; }; - if (yych <= '\f') { gotoCase = 108; continue; }; - { gotoCase = 89; continue; }; + if (yych == '\n') { gotoCase = 99; continue; }; + if (yych <= '\f') { gotoCase = 118; continue; }; + { gotoCase = 99; continue; }; } else { - if (yych == ' ') { gotoCase = 89; continue; }; - if (yych <= '!') { gotoCase = 108; continue; }; - { gotoCase = 89; continue; }; + if (yych == ' ') { gotoCase = 99; continue; }; + if (yych <= '!') { gotoCase = 118; continue; }; + { gotoCase = 99; continue; }; } } else { if (yych <= '>') { - if (yych == '\'') { gotoCase = 89; continue; }; - if (yych <= ';') { gotoCase = 108; continue; }; - { gotoCase = 89; continue; }; + if (yych == '\'') { gotoCase = 99; continue; }; + if (yych <= ';') { gotoCase = 118; continue; }; + { gotoCase = 99; continue; }; } else { if (yych <= '[') { - if (yych <= 'Z') { gotoCase = 108; continue; }; - { gotoCase = 89; continue; }; + if (yych <= 'Z') { gotoCase = 118; continue; }; + { gotoCase = 99; continue; }; } else { - if (yych == ']') { gotoCase = 89; continue; }; - { gotoCase = 108; continue; }; + if (yych == ']') { gotoCase = 99; continue; }; + { gotoCase = 118; continue; }; } } } diff --git a/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.re2js b/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.re2js index 44c62b3..769e984 100644 --- a/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.re2js +++ b/Source/WebCore/inspector/front-end/SourceHTMLTokenizer.re2js @@ -66,7 +66,8 @@ WebInspector.SourceHTMLTokenizer = function() ATTRIBUTE_VALUE: 2, LINKIFY: 4, A_NODE: 8, - SCRIPT: 16 + SCRIPT: 16, + STYLE: 32 }; this.initialCondition = { lexCondition: this._lexConditions.INITIAL, parseCondition: this._parseConditions.INITIAL }; @@ -81,6 +82,12 @@ WebInspector.SourceHTMLTokenizer.prototype = { this._internalJavaScriptTokenizer.line = line.substring(0, match.index); } else this._internalJavaScriptTokenizer.line = line; + } else if (this._internalCSSTokenizer) { + var match = /<\/style/i.exec(line); + if (match) { + this._internalCSSTokenizer.line = line.substring(0, match.index); + } else + this._internalCSSTokenizer.line = line; } this._line = line; }, @@ -145,6 +152,18 @@ WebInspector.SourceHTMLTokenizer.prototype = { return result; } else if (cursor !== this._line.length) delete this._internalJavaScriptTokenizer; + } else if (this._internalCSSTokenizer) { + // Re-set line to force </style> detection first. + this.line = this._line; + if (cursor !== this._internalCSSTokenizer._line.length) { + // Tokenizer is stateless, so restore its condition before tokenizing and save it after. + this._internalCSSTokenizer.condition = this._condition.internalCSSTokenizerCondition; + var result = this._internalCSSTokenizer.nextToken(cursor); + this.tokenType = this._internalCSSTokenizer.tokenType; + this._condition.internalCSSTokenizerCondition = this._internalCSSTokenizer.condition; + return result; + } else if (cursor !== this._line.length) + delete this._internalCSSTokenizer; } var cursorOnEnter = cursor; @@ -175,6 +194,9 @@ WebInspector.SourceHTMLTokenizer.prototype = { ScriptStart = "<" [Ss] [Cc] [Rr] [Ii] [Pp] [Tt]; ScriptEnd = "</" [Ss] [Cc] [Rr] [Ii] [Pp] [Tt]; + StyleStart = "<" [Ss] [Tt] [Yy] [Ll] [Ee]; + StyleEnd = "</" [Ss] [Tt] [Yy] [Ll] [Ee]; + LT = "<" | "</"; GT = ">"; EqualSign = "="; @@ -201,7 +223,7 @@ WebInspector.SourceHTMLTokenizer.prototype = { <INITIAL> ScriptStart => TAG { if (this._condition.parseCondition & this._parseConditions.SCRIPT) { - // Do not tokenize script tag contents, keep lexer state although processing "<". + // Do not tokenize script tag contents, keep lexer state, even though processing "<". this.setLexCondition(this._lexConditions.INITIAL); this.tokenType = null; return cursor; @@ -219,10 +241,31 @@ WebInspector.SourceHTMLTokenizer.prototype = { return cursor; } + <INITIAL> StyleStart => TAG + { + if (this._condition.parseCondition & this._parseConditions.STYLE) { + // Do not tokenize style tag contents, keep lexer state, even though processing "<". + this.setLexCondition(this._lexConditions.INITIAL); + this.tokenType = null; + return cursor; + } + this.tokenType = "html-tag"; + this._condition.parseCondition = this._parseConditions.STYLE; + this._setExpectingAttribute(); + return cursor; + } + + <INITIAL> StyleEnd => TAG + { + this.tokenType = "html-tag"; + this._condition.parseCondition = this._parseConditions.INITIAL; + return cursor; + } + <INITIAL> LT => TAG { - if (this._condition.parseCondition & this._parseConditions.SCRIPT) { - // Do not tokenize script tag contents, keep lexer state although processing "<". + if (this._condition.parseCondition & (this._parseConditions.SCRIPT | this._parseConditions.STYLE)) { + // Do not tokenize script and style tag contents, keep lexer state, even though processing "<". this.setLexCondition(this._lexConditions.INITIAL); this.tokenType = null; return cursor; @@ -245,6 +288,15 @@ WebInspector.SourceHTMLTokenizer.prototype = { return cursor; } + if (this._condition.parseCondition & this._parseConditions.STYLE) { + if (!this._internalCSSTokenizer) { + this._internalCSSTokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/css"); + this._condition.internalCSSTokenizerCondition = this._internalCSSTokenizer.initialCondition; + } + // Do not tokenize style tag contents. + return cursor; + } + this._condition.parseCondition = this._parseConditions.INITIAL; return cursor; } @@ -267,7 +319,7 @@ WebInspector.SourceHTMLTokenizer.prototype = { <TAG> Identifier { - if (this._condition.parseCondition === this._parseConditions.SCRIPT) { + if (this._condition.parseCondition === this._parseConditions.SCRIPT || this._condition.parseCondition === this._parseConditions.STYLE) { // Fall through if expecting attributes. this.tokenType = null; return cursor; diff --git a/Source/WebCore/inspector/front-end/SourceView.js b/Source/WebCore/inspector/front-end/SourceView.js deleted file mode 100644 index 37caabb..0000000 --- a/Source/WebCore/inspector/front-end/SourceView.js +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.SourceView = function(resource) -{ - WebInspector.ResourceView.call(this, resource); - - this.element.addStyleClass("source"); - - var contentProvider = new WebInspector.SourceFrameContentProviderForResource(resource); - var isScript = resource.type === WebInspector.Resource.Type.Script; - this.sourceFrame = new WebInspector.SourceFrame(this.element, contentProvider, resource.url, isScript); -} - -WebInspector.SourceView.prototype = { - show: function(parentElement) - { - WebInspector.View.prototype.show.call(this, parentElement); - this.sourceFrame.visible = true; - }, - - hide: function() - { - this.sourceFrame.visible = false; - this.sourceFrame.clearLineHighlight(); - WebInspector.View.prototype.hide.call(this); - this._currentSearchResultIndex = -1; - }, - - resize: function() - { - this.sourceFrame.resize(); - }, - - get scrollTop() - { - return this.sourceFrame.scrollTop; - }, - - set scrollTop(scrollTop) - { - this.sourceFrame.scrollTop = scrollTop; - }, - - hasContent: function() - { - return true; - }, - - // The rest of the methods in this prototype need to be generic enough to work with a ScriptView. - // The ScriptView prototype pulls these methods into it's prototype to avoid duplicate code. - - searchCanceled: function() - { - this._currentSearchResultIndex = -1; - this._searchResults = []; - this.sourceFrame.clearMarkedRange(); - this.sourceFrame.cancelFindSearchMatches(); - }, - - performSearch: function(query, finishedCallback) - { - // Call searchCanceled since it will reset everything we need before doing a new search. - this.searchCanceled(); - - function didFindSearchMatches(searchResults) - { - this._searchResults = searchResults; - if (this._searchResults) - finishedCallback(this, this._searchResults.length); - } - this.sourceFrame.findSearchMatches(query, didFindSearchMatches.bind(this)); - }, - - jumpToFirstSearchResult: function() - { - if (!this._searchResults || !this._searchResults.length) - return; - this._currentSearchResultIndex = 0; - this._jumpToSearchResult(this._currentSearchResultIndex); - }, - - jumpToLastSearchResult: function() - { - if (!this._searchResults || !this._searchResults.length) - return; - this._currentSearchResultIndex = (this._searchResults.length - 1); - this._jumpToSearchResult(this._currentSearchResultIndex); - }, - - jumpToNextSearchResult: function() - { - if (!this._searchResults || !this._searchResults.length) - return; - if (++this._currentSearchResultIndex >= this._searchResults.length) - this._currentSearchResultIndex = 0; - this._jumpToSearchResult(this._currentSearchResultIndex); - }, - - jumpToPreviousSearchResult: function() - { - if (!this._searchResults || !this._searchResults.length) - return; - if (--this._currentSearchResultIndex < 0) - this._currentSearchResultIndex = (this._searchResults.length - 1); - this._jumpToSearchResult(this._currentSearchResultIndex); - }, - - showingFirstSearchResult: function() - { - return (this._currentSearchResultIndex === 0); - }, - - showingLastSearchResult: function() - { - return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1)); - }, - - revealLine: function(lineNumber) - { - this.sourceFrame.revealLine(lineNumber); - }, - - highlightLine: function(lineNumber) - { - this.sourceFrame.highlightLine(lineNumber); - }, - - addMessage: function(msg) - { - this.sourceFrame.addMessage(msg); - }, - - clearMessages: function() - { - this.sourceFrame.clearMessages(); - }, - - _jumpToSearchResult: function(index) - { - var foundRange = this._searchResults[index]; - if (!foundRange) - return; - - this.sourceFrame.markAndRevealRange(foundRange); - } -} - -WebInspector.SourceView.prototype.__proto__ = WebInspector.ResourceView.prototype; - - -WebInspector.SourceFrameContentProviderForResource = function(resource) -{ - WebInspector.SourceFrameContentProvider.call(this); - this._resource = resource; -} - -//This is a map from resource.type to mime types -//found in WebInspector.SourceTokenizer.Registry. -WebInspector.SourceFrameContentProviderForResource.DefaultMIMETypeForResourceType = { - 0: "text/html", - 1: "text/css", - 4: "text/javascript" -} - -WebInspector.SourceFrameContentProviderForResource.prototype = { - requestContent: function(callback) - { - function contentLoaded(content) - { - var mimeType = WebInspector.SourceFrameContentProviderForResource.DefaultMIMETypeForResourceType[this._resource.type] || this._resource.mimeType; - callback(mimeType, content); - } - this._resource.requestContent(contentLoaded.bind(this)); - }, - - scripts: function() - { - return WebInspector.debuggerModel.scriptsForURL(this._resource.url); - } -} - -WebInspector.SourceFrameContentProviderForResource.prototype.__proto__ = WebInspector.SourceFrameContentProvider.prototype; diff --git a/Source/WebCore/inspector/front-end/StylesSidebarPane.js b/Source/WebCore/inspector/front-end/StylesSidebarPane.js index 9880adc..57d3b76 100644 --- a/Source/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/Source/WebCore/inspector/front-end/StylesSidebarPane.js @@ -1709,10 +1709,6 @@ WebInspector.StylePropertyTreeElement.prototype = { editingEnded: function(context) { - if (this._prompt) { - this._prompt.removeFromElement(); - delete this._prompt; - } this.hasChildren = context.hasChildren; if (context.expanded) this.expand(); @@ -1727,6 +1723,7 @@ WebInspector.StylePropertyTreeElement.prototype = { editingCancelled: function(element, context) { + this._removePrompt(); if ("originalPropertyText" in this) this.applyStyleText(this.originalPropertyText, true); else { @@ -1742,6 +1739,7 @@ WebInspector.StylePropertyTreeElement.prototype = { editingCommitted: function(element, userInput, previousContent, context, moveDirection) { + this._removePrompt(); this.editingEnded(context); var isEditingName = context.isEditingName; @@ -1839,6 +1837,15 @@ WebInspector.StylePropertyTreeElement.prototype = { } }, + _removePrompt: function() + { + // BUG 53242. This cannot go into editingEnded(), as it should always happen first for any editing outcome. + if (this._prompt) { + this._prompt.removeFromElement(); + delete this._prompt; + } + }, + _hasBeenAppliedToPageViaUpDown: function() { // New properties applied via up/down have an originalPropertyText and will be deleted later @@ -1922,16 +1929,34 @@ WebInspector.StylesSidebarPane.CSSPropertyPrompt.prototype = { var reverse = event.keyIdentifier === "Up"; if (this.autoCompleteElement) this.complete(false, reverse); // Accept the current suggestion, if any. + else { + // Select the word suffix to affect it when computing the subsequent suggestion. + this._selectCurrentWordSuffix(); + } + this.complete(false, reverse); // Actually increment/decrement the suggestion. event.handled = true; }, - _buildPropertyCompletions: function(wordRange, bestMatchOnly, completionsReadyCallback) + _selectCurrentWordSuffix: function() { - var prefix = wordRange.toString().toLowerCase(); - if (!prefix.length) + var selection = window.getSelection(); + if (!selection.rangeCount) return; + var selectionRange = selection.getRangeAt(0); + if (!selectionRange.commonAncestorContainer.isDescendant(this.element)) + return; + var wordSuffixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StylesSidebarPane.StyleValueDelimiters, this.element, "forward"); + if (!wordSuffixRange.toString()) + return; + selection.removeAllRanges(); + selection.addRange(wordSuffixRange); + }, + + _buildPropertyCompletions: function(wordRange, bestMatchOnly, completionsReadyCallback) + { + var prefix = wordRange.toString().toLowerCase(); var results; if (bestMatchOnly) { results = []; diff --git a/Source/WebCore/inspector/front-end/TextPrompt.js b/Source/WebCore/inspector/front-end/TextPrompt.js index ac54d8c..36a38cc 100644 --- a/Source/WebCore/inspector/front-end/TextPrompt.js +++ b/Source/WebCore/inspector/front-end/TextPrompt.js @@ -196,7 +196,12 @@ WebInspector.TextPrompt.prototype = { return; var selectionRange = selection.getRangeAt(0); - if (!selectionRange.commonAncestorContainer.isDescendant(this.element)) + var isEmptyInput = selectionRange.commonAncestorContainer === this.element; // this.element has no child Text nodes. + + // Do not attempt to auto-complete an empty input in the auto mode (only on demand). + if (auto && isEmptyInput) + return; + if (!auto && !isEmptyInput && !selectionRange.commonAncestorContainer.isDescendant(this.element)) return; if (auto && !this.isCaretAtEndOfPrompt()) return; diff --git a/Source/WebCore/inspector/front-end/TextViewer.js b/Source/WebCore/inspector/front-end/TextViewer.js index ea36513..ce6502d 100644 --- a/Source/WebCore/inspector/front-end/TextViewer.js +++ b/Source/WebCore/inspector/front-end/TextViewer.js @@ -32,37 +32,23 @@ WebInspector.TextViewer = function(textModel, platform, url) { this._textModel = textModel; - this._textModel.changeListener = this._buildChunks.bind(this); - this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel, this._highlightDataReady.bind(this)); + this._textModel.changeListener = this._textChanged.bind(this); this.element = document.createElement("div"); this.element.className = "text-editor monospace"; - this.element.tabIndex = 0; - - this.element.addEventListener("scroll", this._scroll.bind(this), false); - this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); - this.element.addEventListener("beforecopy", this._beforeCopy.bind(this), false); - this.element.addEventListener("copy", this._copy.bind(this), false); - - this._url = url; - - this._linesContainerElement = document.createElement("table"); - this._linesContainerElement.className = "text-editor-lines"; - this._linesContainerElement.setAttribute("cellspacing", 0); - this._linesContainerElement.setAttribute("cellpadding", 0); - this.element.appendChild(this._linesContainerElement); - - this._defaultChunkSize = 50; - this._paintCoalescingLevel = 0; - this.freeCachedElements(); - this._buildChunks(); + var syncScrollListener = this._syncScroll.bind(this); + var syncDecorationsForLineListener = this._syncDecorationsForLine.bind(this); + this._mainPanel = new WebInspector.TextEditorMainPanel(this._textModel, url, syncScrollListener, syncDecorationsForLineListener); + this._gutterPanel = new WebInspector.TextEditorGutterPanel(this._textModel, syncDecorationsForLineListener); + this.element.appendChild(this._mainPanel.element); + this.element.appendChild(this._gutterPanel.element); } WebInspector.TextViewer.prototype = { set mimeType(mimeType) { - this._highlighter.mimeType = mimeType; + this._mainPanel.mimeType = mimeType; }, get textModel() @@ -72,85 +58,190 @@ WebInspector.TextViewer.prototype = { revealLine: function(lineNumber) { - if (lineNumber >= this._textModel.linesCount) - return; - - var chunk = this._makeLineAChunk(lineNumber); - chunk.element.scrollIntoViewIfNeeded(); + this._mainPanel.revealLine(lineNumber); }, addDecoration: function(lineNumber, decoration) { - var chunk = this._makeLineAChunk(lineNumber); - chunk.addDecoration(decoration); + this._mainPanel.addDecoration(lineNumber, decoration); + this._gutterPanel.addDecoration(lineNumber, decoration); }, removeDecoration: function(lineNumber, decoration) { - var chunk = this._makeLineAChunk(lineNumber); - chunk.removeDecoration(decoration); + this._mainPanel.removeDecoration(lineNumber, decoration); + this._gutterPanel.removeDecoration(lineNumber, decoration); }, markAndRevealRange: function(range) { - if (this._rangeToMark) { - var markedLine = this._rangeToMark.startLine; - this._rangeToMark = null; - this._paintLines(markedLine, markedLine + 1); - } - - if (range) { - this._rangeToMark = range; - this.revealLine(range.startLine); - this._paintLines(range.startLine, range.startLine + 1); - if (this._markedRangeElement) - this._markedRangeElement.scrollIntoViewIfNeeded(); - } - delete this._markedRangeElement; + this._mainPanel.markAndRevealRange(range); }, highlightLine: function(lineNumber) { - this.clearLineHighlight(); - this._highlightedLine = lineNumber; - this.revealLine(lineNumber); - var chunk = this._makeLineAChunk(lineNumber); - chunk.addDecoration("webkit-highlighted-line"); + this._mainPanel.highlightLine(lineNumber); }, clearLineHighlight: function() { - if (typeof this._highlightedLine === "number") { - var chunk = this._makeLineAChunk(this._highlightedLine); - chunk.removeDecoration("webkit-highlighted-line"); - delete this._highlightedLine; - } + this._mainPanel.clearLineHighlight(); }, freeCachedElements: function() { - this._cachedSpans = []; - this._cachedTextNodes = []; - this._cachedRows = []; + this._mainPanel.freeCachedElements(); + this._gutterPanel.freeCachedElements(); + }, + + editLine: function(lineRow, callback) + { + this._mainPanel.editLine(lineRow, callback); + }, + + get scrollTop() + { + return this._mainPanel.element.scrollTop; + }, + + set scrollTop(scrollTop) + { + this._mainPanel.element.scrollTop = scrollTop; + }, + + get scrollLeft() + { + return this._mainPanel.element.scrollLeft; + }, + + set scrollLeft(scrollLeft) + { + this._mainPanel.element.scrollLeft = scrollLeft; + }, + + beginUpdates: function() + { + this._mainPanel.beginUpdates(); + this._gutterPanel.beginUpdates(); + }, + + endUpdates: function() + { + this._mainPanel.endUpdates(); + this._gutterPanel.endUpdates(); + }, + + resize: function() + { + this._mainPanel.resize(); + this._gutterPanel.resize(); + this._updatePanelOffsets(); + }, + + // WebInspector.TextModel listener + _textChanged: function(oldRange, newRange, oldText, newText) + { + this._mainPanel.textChanged(); + this._gutterPanel.textChanged(); + this._updatePanelOffsets(); + }, + + _updatePanelOffsets: function() + { + var lineNumbersWidth = this._gutterPanel.element.offsetWidth; + if (lineNumbersWidth) + this._mainPanel.element.style.setProperty("left", lineNumbersWidth + "px"); + else + this._mainPanel.element.style.removeProperty("left"); // Use default value set in CSS. + }, + + _syncScroll: function() + { + // Async call due to performance reasons. + setTimeout(function() { + var mainElement = this._mainPanel.element; + var gutterElement = this._gutterPanel.element; + + // Handle horizontal scroll bar at the bottom of the main panel. + if (gutterElement.offsetHeight > mainElement.clientHeight) + gutterElement.style.setProperty("padding-bottom", (gutterElement.offsetHeight - mainElement.clientHeight) + "px"); + else + gutterElement.style.removeProperty("padding-bottom"); + + gutterElement.scrollTop = mainElement.scrollTop; + }.bind(this), 0); + }, + + _syncDecorationsForLine: function(lineNumber) + { + if (lineNumber >= this._textModel.linesCount) + return; + + var mainChunk = this._mainPanel.makeLineAChunk(lineNumber); + var gutterChunk = this._gutterPanel.makeLineAChunk(lineNumber); + var height = mainChunk.height; + if (height) + gutterChunk.element.style.setProperty("height", height + "px"); + else + gutterChunk.element.style.removeProperty("height"); + } +} + +WebInspector.TextEditorChunkedPanel = function(textModel) +{ + this._textModel = textModel; + + this._defaultChunkSize = 50; + this._paintCoalescingLevel = 0; +} + +WebInspector.TextEditorChunkedPanel.prototype = { + get textModel() + { + return this._textModel; + }, + + revealLine: function(lineNumber) + { + if (lineNumber >= this._textModel.linesCount) + return; + + var chunk = this.makeLineAChunk(lineNumber); + chunk.element.scrollIntoViewIfNeeded(); + }, + + addDecoration: function(lineNumber, decoration) + { + var chunk = this.makeLineAChunk(lineNumber); + chunk.addDecoration(decoration); + }, + + removeDecoration: function(lineNumber, decoration) + { + var chunk = this.makeLineAChunk(lineNumber); + chunk.removeDecoration(decoration); + }, + + textChanged: function(oldRange, newRange, oldText, newText) + { + this._buildChunks(); }, _buildChunks: function() { - this._linesContainerElement.removeChildren(); + this.element.removeChildren(); this._textChunks = []; for (var i = 0; i < this._textModel.linesCount; i += this._defaultChunkSize) { - var chunk = new WebInspector.TextChunk(this, i, i + this._defaultChunkSize); + var chunk = this._createNewChunk(i, i + this._defaultChunkSize); this._textChunks.push(chunk); - this._linesContainerElement.appendChild(chunk.element); + this.element.appendChild(chunk.element); } - this._indexChunks(); - this._highlighter.reset(); this._repaintAll(); }, - _makeLineAChunk: function(lineNumber) + makeLineAChunk: function(lineNumber) { if (!this._textChunks) this._buildChunks(); @@ -163,31 +254,30 @@ WebInspector.TextViewer.prototype = { var wasExpanded = oldChunk.expanded; oldChunk.expanded = false; - var insertIndex = oldChunk.chunkNumber + 1; + var insertIndex = chunkNumber + 1; // Prefix chunk. if (lineNumber > oldChunk.startLine) { - var prefixChunk = new WebInspector.TextChunk(this, oldChunk.startLine, lineNumber); + var prefixChunk = this._createNewChunk(oldChunk.startLine, lineNumber); this._textChunks.splice(insertIndex++, 0, prefixChunk); - this._linesContainerElement.insertBefore(prefixChunk.element, oldChunk.element); + this.element.insertBefore(prefixChunk.element, oldChunk.element); } // Line chunk. - var lineChunk = new WebInspector.TextChunk(this, lineNumber, lineNumber + 1); + var lineChunk = this._createNewChunk(lineNumber, lineNumber + 1); this._textChunks.splice(insertIndex++, 0, lineChunk); - this._linesContainerElement.insertBefore(lineChunk.element, oldChunk.element); + this.element.insertBefore(lineChunk.element, oldChunk.element); // Suffix chunk. if (oldChunk.startLine + oldChunk.linesCount > lineNumber + 1) { - var suffixChunk = new WebInspector.TextChunk(this, lineNumber + 1, oldChunk.startLine + oldChunk.linesCount); + var suffixChunk = this._createNewChunk(lineNumber + 1, oldChunk.startLine + oldChunk.linesCount); this._textChunks.splice(insertIndex, 0, suffixChunk); - this._linesContainerElement.insertBefore(suffixChunk.element, oldChunk.element); + this.element.insertBefore(suffixChunk.element, oldChunk.element); } // Remove enclosing chunk. - this._textChunks.splice(oldChunk.chunkNumber, 1); - this._linesContainerElement.removeChild(oldChunk.element); - this._indexChunks(); + this._textChunks.splice(chunkNumber, 1); + this.element.removeChild(oldChunk.element); if (wasExpanded) { if (prefixChunk) @@ -200,19 +290,315 @@ WebInspector.TextViewer.prototype = { return lineChunk; }, - _indexChunks: function() + _scroll: function() { - for (var i = 0; i < this._textChunks.length; ++i) - this._textChunks[i].chunkNumber = i; + this._scheduleRepaintAll(); + if (this._syncScrollListener) + this._syncScrollListener(); }, - _scroll: function() + _scheduleRepaintAll: function() { - var scrollTop = this.element.scrollTop; - setTimeout(function() { - if (scrollTop === this.element.scrollTop) - this._repaintAll(); - }.bind(this), 50); + if (this._repaintAllTimer) + clearTimeout(this._repaintAllTimer); + this._repaintAllTimer = setTimeout(this._repaintAll.bind(this), 50); + }, + + beginUpdates: function() + { + this._paintCoalescingLevel++; + }, + + endUpdates: function() + { + this._paintCoalescingLevel--; + if (!this._paintCoalescingLevel) + this._repaintAll(); + }, + + _chunkNumberForLine: function(lineNumber) + { + for (var i = 0; i < this._textChunks.length; ++i) { + var line = this._textChunks[i].startLine; + if (lineNumber >= line && lineNumber < line + this._textChunks[i].linesCount) + return i; + } + return this._textChunks.length - 1; + }, + + _chunkForLine: function(lineNumber) + { + return this._textChunks[this._chunkNumberForLine(lineNumber)]; + }, + + _repaintAll: function() + { + delete this._repaintAllTimer; + + if (this._paintCoalescingLevel) + return; + + if (!this._textChunks) + this._buildChunks(); + + var visibleFrom = this.element.scrollTop; + var visibleTo = this.element.scrollTop + this.element.clientHeight; + + var offset = 0; + var fromIndex = -1; + var toIndex = 0; + for (var i = 0; i < this._textChunks.length; ++i) { + var chunk = this._textChunks[i]; + var chunkHeight = chunk.height; + if (offset + chunkHeight > visibleFrom && offset < visibleTo) { + if (fromIndex === -1) + fromIndex = i; + toIndex = i + 1; + } else { + if (offset >= visibleTo) + break; + } + offset += chunkHeight; + } + + if (toIndex) + this._expandChunks(fromIndex, toIndex); + }, + + _totalHeight: function(firstElement, lastElement) + { + lastElement = (lastElement || firstElement).nextElementSibling; + if (lastElement) + return lastElement.offsetTop - firstElement.offsetTop; + else if (firstElement.offsetParent) + return firstElement.offsetParent.scrollHeight - firstElement.offsetTop; + return firstElement.offsetHeight; + }, + + resize: function() + { + this._repaintAll(); + } +} + +WebInspector.TextEditorGutterPanel = function(textModel, syncDecorationsForLineListener) +{ + WebInspector.TextEditorChunkedPanel.call(this, textModel); + + this._syncDecorationsForLineListener = syncDecorationsForLineListener; + + this.element = document.createElement("div"); + this.element.className = "text-editor-lines"; + + this.element.addEventListener("scroll", this._scroll.bind(this), false); + + this.freeCachedElements(); + this._buildChunks(); +} + +WebInspector.TextEditorGutterPanel.prototype = { + freeCachedElements: function() + { + this._cachedRows = []; + }, + + _createNewChunk: function(startLine, endLine) + { + return new WebInspector.TextEditorGutterChunk(this, startLine, endLine); + }, + + _expandChunks: function(fromIndex, toIndex) + { + for (var i = 0; i < this._textChunks.length; ++i) { + this._textChunks[i].expanded = (fromIndex <= i && i < toIndex); + } + } +} + +WebInspector.TextEditorGutterPanel.prototype.__proto__ = WebInspector.TextEditorChunkedPanel.prototype; + +WebInspector.TextEditorGutterChunk = function(textViewer, startLine, endLine) +{ + this._textViewer = textViewer; + this._textModel = textViewer._textModel; + + this.startLine = startLine; + endLine = Math.min(this._textModel.linesCount, endLine); + this.linesCount = endLine - startLine; + + this._expanded = false; + + this.element = document.createElement("div"); + this.element.lineNumber = startLine; + this.element.className = "webkit-line-number"; + + if (this.linesCount === 1) { + // Single line chunks are typically created for decorations. Host line number in + // the sub-element in order to allow flexible border / margin management. + var innerSpan = document.createElement("span"); + innerSpan.className = "webkit-line-number-inner"; + innerSpan.textContent = startLine + 1; + var outerSpan = document.createElement("div"); + outerSpan.className = "webkit-line-number-outer"; + outerSpan.appendChild(innerSpan); + this.element.appendChild(outerSpan); + } else { + var lineNumbers = []; + for (var i = startLine; i < endLine; ++i) { + lineNumbers.push(i + 1); + } + this.element.textContent = lineNumbers.join("\n"); + } +} + +WebInspector.TextEditorGutterChunk.prototype = { + addDecoration: function(decoration) + { + if (typeof decoration === "string") { + this.element.addStyleClass(decoration); + } + }, + + removeDecoration: function(decoration) + { + if (typeof decoration === "string") { + this.element.removeStyleClass(decoration); + } + }, + + get expanded() + { + return this._expanded; + }, + + set expanded(expanded) + { + if (this.linesCount === 1) + this._textViewer._syncDecorationsForLineListener(this.startLine); + + if (this._expanded === expanded) + return; + + this._expanded = expanded; + + if (this.linesCount === 1) + return; + + if (expanded) { + this._expandedLineRows = []; + var parentElement = this.element.parentElement; + for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) { + var lineRow = this._createRow(i); + parentElement.insertBefore(lineRow, this.element); + this._expandedLineRows.push(lineRow); + } + parentElement.removeChild(this.element); + } else { + var elementInserted = false; + for (var i = 0; i < this._expandedLineRows.length; ++i) { + var lineRow = this._expandedLineRows[i]; + var parentElement = lineRow.parentElement; + if (parentElement) { + if (!elementInserted) { + elementInserted = true; + parentElement.insertBefore(this.element, lineRow); + } + this._textViewer._cachedRows.push(lineRow); + parentElement.removeChild(lineRow); + } + } + delete this._expandedLineRows; + } + }, + + get height() + { + if (!this._expandedLineRows) + return this._textViewer._totalHeight(this.element); + return this._textViewer._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]); + }, + + _createRow: function(lineNumber) + { + var lineRow = this._textViewer._cachedRows.pop() || document.createElement("div"); + lineRow.lineNumber = lineNumber; + lineRow.className = "webkit-line-number"; + lineRow.textContent = lineNumber + 1; + return lineRow; + } +} + +WebInspector.TextEditorMainPanel = function(textModel, url, syncScrollListener, syncDecorationsForLineListener) +{ + WebInspector.TextEditorChunkedPanel.call(this, textModel); + + this._syncScrollListener = syncScrollListener; + this._syncDecorationsForLineListener = syncDecorationsForLineListener; + + this._url = url; + this._highlighter = new WebInspector.TextEditorHighlighter(textModel, this._highlightDataReady.bind(this)); + + this.element = document.createElement("div"); + this.element.className = "text-editor-contents"; + this.element.tabIndex = 0; + + this.element.addEventListener("scroll", this._scroll.bind(this), false); + this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); + + var handleDOMUpdates = this._handleDOMUpdates.bind(this); + this.element.addEventListener("DOMCharacterDataModified", handleDOMUpdates, false); + this.element.addEventListener("DOMNodeInserted", handleDOMUpdates, false); + this.element.addEventListener("DOMNodeRemoved", handleDOMUpdates, false); + + this.freeCachedElements(); + this._buildChunks(); +} + +WebInspector.TextEditorMainPanel.prototype = { + set mimeType(mimeType) + { + this._highlighter.mimeType = mimeType; + }, + + markAndRevealRange: function(range) + { + if (this._rangeToMark) { + var markedLine = this._rangeToMark.startLine; + this._rangeToMark = null; + this._paintLines(markedLine, markedLine + 1); + } + + if (range) { + this._rangeToMark = range; + this.revealLine(range.startLine); + this._paintLines(range.startLine, range.startLine + 1); + if (this._markedRangeElement) + this._markedRangeElement.scrollIntoViewIfNeeded(); + } + delete this._markedRangeElement; + }, + + highlightLine: function(lineNumber) + { + this.clearLineHighlight(); + this._highlightedLine = lineNumber; + this.revealLine(lineNumber); + this.addDecoration(lineNumber, "webkit-highlighted-line"); + }, + + clearLineHighlight: function() + { + if (typeof this._highlightedLine === "number") { + this.removeDecoration(this._highlightedLine, "webkit-highlighted-line"); + delete this._highlightedLine; + } + }, + + freeCachedElements: function() + { + this._cachedSpans = []; + this._cachedTextNodes = []; + this._cachedRows = []; }, _handleKeyDown: function() @@ -248,16 +634,15 @@ WebInspector.TextViewer.prototype = { editLine: function(lineRow, callback) { - var element = lineRow.lastChild; - var oldContent = element.innerHTML; + var oldContent = lineRow.innerHTML; function finishEditing(committed, e, newContent) { if (committed) callback(newContent); - element.innerHTML = oldContent; + lineRow.innerHTML = oldContent; delete this._editingLine; } - this._editingLine = WebInspector.startEditing(element, { + this._editingLine = WebInspector.startEditing(lineRow, { context: null, commitHandler: finishEditing.bind(this, true), cancelHandler: finishEditing.bind(this, false), @@ -265,102 +650,21 @@ WebInspector.TextViewer.prototype = { }); }, - _beforeCopy: function(e) - { - e.preventDefault(); - }, - - _copy: function(e) - { - var range = this._getSelection(); - var text = this._textModel.copyRange(range); - InspectorFrontendHost.copyText(text); - e.preventDefault(); - }, - - beginUpdates: function(enabled) - { - this._paintCoalescingLevel++; - }, - - endUpdates: function(enabled) - { - this._paintCoalescingLevel--; - if (!this._paintCoalescingLevel) - this._repaintAll(); - }, - - _chunkForOffset: function(offset) - { - var currentOffset = 0; - var row = this._linesContainerElement.firstChild; - while (row) { - var rowHeight = row.offsetHeight; - if (offset >= currentOffset && offset < currentOffset + rowHeight) - return row.chunkNumber; - row = row.nextSibling; - currentOffset += rowHeight; - } - return this._textChunks.length - 1; - }, - - _chunkNumberForLine: function(lineNumber) - { - for (var i = 0; i < this._textChunks.length; ++i) { - var line = this._textChunks[i].startLine; - if (lineNumber >= this._textChunks[i].startLine && lineNumber < this._textChunks[i].startLine + this._textChunks[i].linesCount) - return i; - } - return this._textChunks.length - 1; - }, - - _chunkForLine: function(lineNumber) + _buildChunks: function() { - return this._textChunks[this._chunkNumberForLine(lineNumber)]; + this._highlighter.reset(); + WebInspector.TextEditorChunkedPanel.prototype._buildChunks.call(this); }, - _chunkStartLine: function(chunkNumber) + _createNewChunk: function(startLine, endLine) { - var lineNumber = 0; - for (var i = 0; i < chunkNumber && i < this._textChunks.length; ++i) - lineNumber += this._textChunks[i].linesCount; - return lineNumber; + return new WebInspector.TextEditorMainChunk(this, startLine, endLine); }, - _repaintAll: function() + _expandChunks: function(fromIndex, toIndex) { - if (this._paintCoalescingLevel) - return; - - if (!this._textChunks) - this._buildChunks(); - - var visibleFrom = this.element.scrollTop; - var visibleTo = this.element.scrollTop + this.element.clientHeight; - - var offset = 0; - var firstVisibleLine = -1; - var lastVisibleLine = 0; - var toExpand = []; - var toCollapse = []; - for (var i = 0; i < this._textChunks.length; ++i) { - var chunk = this._textChunks[i]; - var chunkHeight = chunk.height; - if (offset + chunkHeight > visibleFrom && offset < visibleTo) { - toExpand.push(chunk); - if (firstVisibleLine === -1) - firstVisibleLine = chunk.startLine; - lastVisibleLine = chunk.startLine + chunk.linesCount; - } else { - toCollapse.push(chunk); - if (offset >= visibleTo) - break; - } - offset += chunkHeight; - } - - for (var j = i; j < this._textChunks.length; ++j) - toCollapse.push(this._textChunks[i]); + var lastChunk = this._textChunks[toIndex - 1]; + var lastVisibleLine = lastChunk.startLine + lastChunk.linesCount; var selection = this._getSelection(); @@ -368,10 +672,9 @@ WebInspector.TextViewer.prototype = { this._highlighter.highlight(lastVisibleLine); delete this._muteHighlightListener; - for (var i = 0; i < toCollapse.length; ++i) - toCollapse[i].expanded = false; - for (var i = 0; i < toExpand.length; ++i) - toExpand[i].expanded = true; + for (var i = 0; i < this._textChunks.length; ++i) { + this._textChunks[i].expanded = (fromIndex <= i && i < toIndex); + } this._restoreSelection(selection); }, @@ -380,40 +683,40 @@ WebInspector.TextViewer.prototype = { { if (this._muteHighlightListener) return; + this._paintLines(fromLine, toLine, true /*restoreSelection*/); + }, + _paintLines: function(fromLine, toLine, restoreSelection) + { var selection; + var chunk = this._chunkForLine(fromLine); for (var i = fromLine; i < toLine; ++i) { - var lineRow = this._textModel.getAttribute(i, "line-row"); - if (!lineRow || lineRow.highlighted) + if (i >= chunk.startLine + chunk.linesCount) + chunk = this._chunkForLine(i); + var lineRow = chunk.getExpandedLineRow(i); + if (!lineRow) continue; - if (!selection) + if (restoreSelection && !selection) selection = this._getSelection(); this._paintLine(lineRow, i); } - this._restoreSelection(selection); - }, - - _paintLines: function(fromLine, toLine) - { - for (var i = fromLine; i < toLine; ++i) { - var lineRow = this._textModel.getAttribute(i, "line-row"); - if (lineRow) - this._paintLine(lineRow, i); - } + if (restoreSelection) + this._restoreSelection(selection); }, _paintLine: function(lineRow, lineNumber) { - var element = lineRow.lastChild; var highlight = this._textModel.getAttribute(lineNumber, "highlight"); if (!highlight) { if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) - this._markedRangeElement = highlightSearchResult(element, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); + this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); return; } - element.removeChildren(); + lineRow.removeChildren(); var line = this._textModel.line(lineNumber); + if (!line) + lineRow.appendChild(document.createElement("br")); var plainTextStart = -1; for (var j = 0; j < line.length;) { @@ -430,98 +733,64 @@ WebInspector.TextViewer.prototype = { j++; } else { if (plainTextStart !== -1) { - this._appendTextNode(element, line.substring(plainTextStart, j)); + this._appendTextNode(lineRow, line.substring(plainTextStart, j)); plainTextStart = -1; } - this._appendSpan(element, line.substring(j, j + attribute.length), attribute.tokenType); + this._appendSpan(lineRow, line.substring(j, j + attribute.length), attribute.tokenType); j += attribute.length; } } if (plainTextStart !== -1) - this._appendTextNode(element, line.substring(plainTextStart, line.length)); + this._appendTextNode(lineRow, line.substring(plainTextStart, line.length)); if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) - this._markedRangeElement = highlightSearchResult(element, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); + this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); if (lineRow.decorationsElement) - element.appendChild(lineRow.decorationsElement); + lineRow.appendChild(lineRow.decorationsElement); }, - _releaseLinesHighlight: function(fromLine, toLine) + _releaseLinesHighlight: function(lineRow) { - for (var i = fromLine; i < toLine; ++i) { - var lineRow = this._textModel.getAttribute(i, "line-row"); - if (!lineRow) - continue; - var element = lineRow.lastChild; - if ("spans" in element) { - var spans = element.spans; - for (var j = 0; j < spans.length; ++j) - this._cachedSpans.push(spans[j]); - delete element.spans; - } - if ("textNodes" in element) { - var textNodes = element.textNodes; - for (var j = 0; j < textNodes.length; ++j) - this._cachedTextNodes.push(textNodes[j]); - delete element.textNodes; - } + if (!lineRow) + return; + if ("spans" in lineRow) { + var spans = lineRow.spans; + for (var j = 0; j < spans.length; ++j) + this._cachedSpans.push(spans[j]); + delete lineRow.spans; } + if ("textNodes" in lineRow) { + var textNodes = lineRow.textNodes; + for (var j = 0; j < textNodes.length; ++j) + this._cachedTextNodes.push(textNodes[j]); + delete lineRow.textNodes; + } + this._cachedRows.push(lineRow); }, _getSelection: function() { var selection = window.getSelection(); - if (selection.isCollapsed) + if (!selection.rangeCount) return null; var selectionRange = selection.getRangeAt(0); // Selection may be outside of the viewer. if (!this.element.isAncestor(selectionRange.startContainer) || !this.element.isAncestor(selectionRange.endContainer)) return null; var start = this._selectionToPosition(selectionRange.startContainer, selectionRange.startOffset); - var end = this._selectionToPosition(selectionRange.endContainer, selectionRange.endOffset); - return new WebInspector.TextRange(start.line, start.column, end.line, end.column); + var end = selectionRange.collapsed ? start : this._selectionToPosition(selectionRange.endContainer, selectionRange.endOffset); + if (selection.anchorNode === selectionRange.startContainer && selection.anchorOffset === selectionRange.startOffset) + return new WebInspector.TextRange(start.line, start.column, end.line, end.column); + else + return new WebInspector.TextRange(end.line, end.column, start.line, start.column); }, _restoreSelection: function(range) { if (!range) return; - var startRow = this._textModel.getAttribute(range.startLine, "line-row"); - if (startRow) - var start = startRow.lastChild.rangeBoundaryForOffset(range.startColumn); - else { - var offset = range.startColumn; - var chunkNumber = this._chunkNumberForLine(range.startLine); - for (var i = this._chunkStartLine(chunkNumber); i < range.startLine; ++i) - offset += this._textModel.line(i).length + 1; // \n - var lineCell = this._textChunks[chunkNumber].element.lastChild; - if (lineCell.firstChild) - var start = { container: lineCell.firstChild, offset: offset }; - else - var start = { container: lineCell, offset: 0 }; - } - - var endRow = this._textModel.getAttribute(range.endLine, "line-row"); - if (endRow) - var end = endRow.lastChild.rangeBoundaryForOffset(range.endColumn); - else { - var offset = range.endColumn; - var chunkNumber = this._chunkNumberForLine(range.endLine); - for (var i = this._chunkStartLine(chunkNumber); i < range.endLine; ++i) - offset += this._textModel.line(i).length + 1; // \n - var lineCell = this._textChunks[chunkNumber].element.lastChild; - if (lineCell.firstChild) - var end = { container: lineCell.firstChild, offset: offset }; - else - var end = { container: lineCell, offset: 0 }; - } - - var selectionRange = document.createRange(); - selectionRange.setStart(start.container, start.offset); - selectionRange.setEnd(end.container, end.offset); - - var selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(selectionRange); + var start = this._positionToSelection(range.startLine, range.startColumn); + var end = range.isEmpty() ? start : this._positionToSelection(range.endLine, range.endColumn); + window.getSelection().setBaseAndExtent(start.container, start.offset, end.container, end.offset); }, _selectionToPosition: function(container, offset) @@ -531,21 +800,26 @@ WebInspector.TextViewer.prototype = { if (container === this.element && offset === 1) return { line: this._textModel.linesCount - 1, column: this._textModel.lineLength(this._textModel.linesCount - 1) }; - var lineRow = container.enclosingNodeOrSelfWithNodeName("tr"); + var lineRow = container.enclosingNodeOrSelfWithNodeName("DIV"); var lineNumber = lineRow.lineNumber; - if (container.nodeName === "TD" && offset === 0) + if (container === lineRow && offset === 0) return { line: lineNumber, column: 0 }; - if (container.nodeName === "TD" && offset === 1) - return { line: lineNumber, column: this._textModel.lineLength(lineNumber) }; + // This may be chunk and chunks may contain \n. var column = 0; - var node = lineRow.lastChild.traverseNextTextNode(lineRow.lastChild); + var node = lineRow.traverseNextTextNode(lineRow); while (node && node !== container) { - column += node.textContent.length; - node = node.traverseNextTextNode(lineRow.lastChild); + var text = node.textContent; + for (var i = 0; i < text.length; ++i) { + if (text.charAt(i) === "\n") { + lineNumber++; + column = 0; + } else + column++; + } + node = node.traverseNextTextNode(lineRow); } - // This may be chunk and chunks may contain \n. if (node === container && offset) { var text = node.textContent; for (var i = 0; i < offset; ++i) { @@ -559,6 +833,25 @@ WebInspector.TextViewer.prototype = { return { line: lineNumber, column: column }; }, + _positionToSelection: function(line, column) + { + var chunk = this._chunkForLine(line); + var lineRow = chunk.getExpandedLineRow(line); + if (lineRow) + var rangeBoundary = lineRow.rangeBoundaryForOffset(column); + else { + var offset = column; + for (var i = chunk.startLine; i < line; ++i) + offset += this._textModel.lineLength(i) + 1; // \n + lineRow = chunk.element; + if (lineRow.firstChild) + var rangeBoundary = { container: lineRow.firstChild, offset: offset }; + else + var rangeBoundary = { container: lineRow, offset: 0 }; + } + return rangeBoundary; + }, + _appendSpan: function(element, content, className) { if (className === "html-resource-link" || className === "html-external-link") { @@ -578,9 +871,9 @@ WebInspector.TextViewer.prototype = { _appendTextNode: function(element, text) { var textNode = this._cachedTextNodes.pop(); - if (textNode) { + if (textNode) textNode.nodeValue = text; - } else + else textNode = document.createTextNode(text); element.appendChild(textNode); if (!("textNodes" in element)) @@ -614,58 +907,52 @@ WebInspector.TextViewer.prototype = { return WebInspector.completeURL(this._url, hrefValue); }, - resize: function() + _handleDOMUpdates: function(e) { - this._repaintAll(); + var target = e.target; + var lineRow = target.enclosingNodeOrSelfWithClass("webkit-line-content"); + if (lineRow === target || !lineRow || !lineRow.decorationsElement || !lineRow.decorationsElement.isAncestor(target)) + return; + if (this._syncDecorationsForLineListener) { + // Wait until this event is processed and only then sync the sizes. This is necessary in + // case of the DOMNodeRemoved event, because it is dispatched before the removal takes place. + setTimeout(function() { + this._syncDecorationsForLineListener(lineRow.lineNumber); + }.bind(this), 0); + } } } -var cachedSpans = []; +WebInspector.TextEditorMainPanel.prototype.__proto__ = WebInspector.TextEditorChunkedPanel.prototype; -WebInspector.TextChunk = function(textViewer, startLine, endLine) +WebInspector.TextEditorMainChunk = function(textViewer, startLine, endLine) { this._textViewer = textViewer; - this.element = document.createElement("tr"); this._textModel = textViewer._textModel; - this.element.chunk = this; + + this.element = document.createElement("div"); this.element.lineNumber = startLine; + this.element.className = "webkit-line-content"; this.startLine = startLine; endLine = Math.min(this._textModel.linesCount, endLine); this.linesCount = endLine - startLine; - this._lineNumberElement = document.createElement("td"); - this._lineNumberElement.className = "webkit-line-number"; - this.element.appendChild(this._lineNumberElement); - - this._lineContentElement = document.createElement("td"); - this._lineContentElement.className = "webkit-line-content"; - this.element.appendChild(this._lineContentElement); - this._expanded = false; - var lineNumbers = []; var lines = []; for (var i = startLine; i < endLine; ++i) { - lineNumbers.push(i + 1); lines.push(this._textModel.line(i)); } - if (this.linesCount === 1) { - // Single line chunks are typically created for decorations. Host line number in - // the sub-element in order to allow flexible border / margin management. - var innerSpan = document.createElement("span"); - innerSpan.className = "webkit-line-number-inner"; - innerSpan.textContent = startLine + 1; - var outerSpan = document.createElement("div"); - outerSpan.className = "webkit-line-number-outer"; - outerSpan.appendChild(innerSpan); - this._lineNumberElement.appendChild(outerSpan); - } else - this._lineNumberElement.textContent = lineNumbers.join("\n"); - this._lineContentElement.textContent = lines.join("\n"); + + this.element.textContent = lines.join("\n"); + + // The last empty line will get swallowed otherwise. + if (!lines[lines.length - 1]) + this.element.appendChild(document.createElement("br")); } -WebInspector.TextChunk.prototype = { +WebInspector.TextEditorMainChunk.prototype = { addDecoration: function(decoration) { if (typeof decoration === "string") { @@ -674,7 +961,8 @@ WebInspector.TextChunk.prototype = { } if (!this.element.decorationsElement) { this.element.decorationsElement = document.createElement("div"); - this._lineContentElement.appendChild(this.element.decorationsElement); + this.element.decorationsElement.className = "webkit-line-decorations"; + this.element.appendChild(this.element.decorationsElement); } this.element.decorationsElement.appendChild(decoration); }, @@ -703,71 +991,63 @@ WebInspector.TextChunk.prototype = { this._expanded = expanded; if (this.linesCount === 1) { - this._textModel.setAttribute(this.startLine, "line-row", this.element); if (expanded) - this._textViewer._paintLines(this.startLine, this.startLine + 1); + this._textViewer._paintLine(this.element, this.startLine); return; } if (expanded) { + this._expandedLineRows = []; var parentElement = this.element.parentElement; for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) { var lineRow = this._createRow(i); - this._textModel.setAttribute(i, "line-row", lineRow); parentElement.insertBefore(lineRow, this.element); + this._expandedLineRows.push(lineRow); + this._textViewer._paintLine(lineRow, i); } parentElement.removeChild(this.element); - - this._textViewer._paintLines(this.startLine, this.startLine + this.linesCount); } else { - var firstLine = this._textModel.getAttribute(this.startLine, "line-row"); - var parentElement = firstLine.parentElement; - this._textViewer._releaseLinesHighlight(this.startLine, this.startLine + this.linesCount); - - parentElement.insertBefore(this.element, firstLine); - for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) { - var lineRow = this._textModel.getAttribute(i, "line-row"); - this._textModel.removeAttribute(i, "line-row"); - this._textViewer._cachedRows.push(lineRow); - parentElement.removeChild(lineRow); + var elementInserted = false; + for (var i = 0; i < this._expandedLineRows.length; ++i) { + var lineRow = this._expandedLineRows[i]; + var parentElement = lineRow.parentElement; + if (parentElement) { + if (!elementInserted) { + elementInserted = true; + parentElement.insertBefore(this.element, lineRow); + } + this._textViewer._releaseLinesHighlight(lineRow); + parentElement.removeChild(lineRow); + } } + delete this._expandedLineRows; } }, get height() { - if (!this._expanded) - return this.element.offsetHeight; - var result = 0; - for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) { - var lineRow = this._textModel.getAttribute(i, "line-row"); - result += lineRow.offsetHeight; - } - return result; + if (!this._expandedLineRows) + return this._textViewer._totalHeight(this.element); + return this._textViewer._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]); }, _createRow: function(lineNumber) { - var cachedRows = this._textViewer._cachedRows; - if (cachedRows.length) { - var lineRow = cachedRows[cachedRows.length - 1]; - cachedRows.length--; - var lineNumberElement = lineRow.firstChild; - var lineContentElement = lineRow.lastChild; - } else { - var lineRow = document.createElement("tr"); - - var lineNumberElement = document.createElement("td"); - lineNumberElement.className = "webkit-line-number"; - lineRow.appendChild(lineNumberElement); - - var lineContentElement = document.createElement("td"); - lineContentElement.className = "webkit-line-content"; - lineRow.appendChild(lineContentElement); - } + var lineRow = this._textViewer._cachedRows.pop() || document.createElement("div"); lineRow.lineNumber = lineNumber; - lineNumberElement.textContent = lineNumber + 1; - lineContentElement.textContent = this._textModel.line(lineNumber); + lineRow.className = "webkit-line-content"; + lineRow.textContent = this._textModel.line(lineNumber); + if (!lineRow.textContent) + lineRow.appendChild(document.createElement("br")); return lineRow; + }, + + getExpandedLineRow: function(lineNumber) + { + if (!this._expanded || lineNumber < this.startLine || lineNumber >= this.startLine + this.linesCount) + return null; + if (!this._expandedLineRows) + return this.element; + return this._expandedLineRows[lineNumber - this.startLine]; } } diff --git a/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js b/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js index a218c01..a559145 100644 --- a/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js +++ b/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js @@ -182,7 +182,6 @@ var OPERATORS = array_to_hash([ ">>=", "<<=", ">>>=", - "~=", "%=", "|=", "^=", @@ -253,18 +252,19 @@ function is_token(token, type, val) { var EX_EOF = {}; -function tokenizer($TEXT, skip_comments) { +function tokenizer($TEXT) { var S = { - text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), - pos : 0, - tokpos : 0, - line : 0, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + comments_before : [] }; function peek() { return S.text.charAt(S.pos); }; @@ -299,7 +299,7 @@ function tokenizer($TEXT, skip_comments) { S.tokpos = S.pos; }; - function token(type, value) { + function token(type, value, is_comment) { S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); @@ -311,6 +311,10 @@ function tokenizer($TEXT, skip_comments) { pos : S.tokpos, nlb : S.newline_before }; + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + } S.newline_before = false; return ret; }; @@ -334,7 +338,7 @@ function tokenizer($TEXT, skip_comments) { }; function read_num(prefix) { - var has_e = false, after_e = false, has_x = false; + var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; var num = read_while(function(ch, i){ if (ch == "x" || ch == "X") { if (has_x) return false; @@ -350,7 +354,12 @@ function tokenizer($TEXT, skip_comments) { } if (ch == "+") return after_e; after_e = false; - return is_alphanumeric_char(ch) || ch == "."; + if (ch == ".") { + if (!has_dot) + return has_dot = true; + return false; + } + return is_alphanumeric_char(ch); }); if (prefix) num = prefix + num; @@ -412,7 +421,7 @@ function tokenizer($TEXT, skip_comments) { ret = S.text.substring(S.pos, i); S.pos = i; } - return token("comment1", ret); + return token("comment1", ret, true); }; function read_multiline_comment() { @@ -420,8 +429,9 @@ function tokenizer($TEXT, skip_comments) { return with_eof_error("Unterminated multiline comment", function(){ var i = find("*/", true), text = S.text.substring(S.pos, i), - tok = token("comment2", text); + tok = token("comment2", text, true); S.pos = i + 2; + S.line += text.split("\n").length - 1; S.newline_before = text.indexOf("\n") >= 0; return tok; }); @@ -455,6 +465,7 @@ function tokenizer($TEXT, skip_comments) { function read_operator(prefix) { function grow(op) { + if (!peek()) return op; var bigger = op + peek(); if (HOP(OPERATORS, bigger)) { next(); @@ -466,19 +477,18 @@ function tokenizer($TEXT, skip_comments) { return token("operator", grow(prefix || next())); }; - var handle_slash = skip_comments ? function() { + function handle_slash() { next(); var regex_allowed = S.regex_allowed; switch (peek()) { - case "/": read_line_comment(); S.regex_allowed = regex_allowed; return next_token(); - case "*": read_multiline_comment(); S.regex_allowed = regex_allowed; return next_token(); - } - return S.regex_allowed ? read_regexp() : read_operator("/"); - } : function() { - next(); - switch (peek()) { - case "/": return read_line_comment(); - case "*": return read_multiline_comment(); + case "/": + S.comments_before.push(read_line_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + case "*": + S.comments_before.push(read_multiline_comment()); + S.regex_allowed = regex_allowed; + return next_token(); } return S.regex_allowed ? read_regexp() : read_operator("/"); }; @@ -559,7 +569,7 @@ var ASSIGNMENT = (function(a, ret, i){ } return ret; })( - ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "~=", "%=", "|=", "^=", "&="], + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], { "=": true }, 0 ); @@ -605,13 +615,13 @@ NodeWithToken.prototype.toString = function() { return this.name; }; function parse($TEXT, strict_mode, embed_tokens) { var S = { - input: tokenizer($TEXT, true), - token: null, - prev: null, - peeked: null, - in_function: 0, - in_loop: 0, - labels: [] + input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, + token : null, + prev : null, + peeked : null, + in_function : 0, + in_loop : 0, + labels : [] }; S.token = next(); @@ -1016,20 +1026,23 @@ function parse($TEXT, strict_mode, embed_tokens) { unexpected(); }; - function expr_list(closing, allow_trailing_comma) { + function expr_list(closing, allow_trailing_comma, allow_empty) { var first = true, a = []; while (!is("punc", closing)) { if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) - break; - a.push(expression(false)); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push([ "atom", "undefined" ]); + } else { + a.push(expression(false)); + } } next(); return a; }; function array_() { - return as("array", expr_list("]", !strict_mode)); + return as("array", expr_list("]", !strict_mode, true)); }; function object_() { @@ -1231,3 +1244,4 @@ exports.KEYWORDS = KEYWORDS; exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN; exports.OPERATORS = OPERATORS; exports.is_alphanumeric_char = is_alphanumeric_char; +exports.is_identifier_char = is_identifier_char; diff --git a/Source/WebCore/inspector/front-end/UglifyJS/process.js b/Source/WebCore/inspector/front-end/UglifyJS/process.js index 65dbc0e..5e32dd0 100755 --- a/Source/WebCore/inspector/front-end/UglifyJS/process.js +++ b/Source/WebCore/inspector/front-end/UglifyJS/process.js @@ -69,139 +69,135 @@ var jsp = require("./parse-js"), function ast_walker(ast) { function _vardefs(defs) { - return MAP(defs, function(def){ + return [ this[0], MAP(defs, function(def){ var a = [ def[0] ]; if (def.length > 1) a[1] = walk(def[1]); return a; - }); + }) ]; }; var walkers = { "string": function(str) { - return [ "string", str ]; + return [ this[0], str ]; }, "num": function(num) { - return [ "num", num ]; + return [ this[0], num ]; }, "name": function(name) { - return [ "name", name ]; + return [ this[0], name ]; }, "toplevel": function(statements) { - return [ "toplevel", MAP(statements, walk) ]; + return [ this[0], MAP(statements, walk) ]; }, "block": function(statements) { - var out = [ "block" ]; + var out = [ this[0] ]; if (statements != null) out.push(MAP(statements, walk)); return out; }, - "var": function(defs) { - return [ "var", _vardefs(defs) ]; - }, - "const": function(defs) { - return [ "const", _vardefs(defs) ]; - }, + "var": _vardefs, + "const": _vardefs, "try": function(t, c, f) { return [ - "try", + this[0], MAP(t, walk), c != null ? [ c[0], MAP(c[1], walk) ] : null, f != null ? MAP(f, walk) : null ]; }, "throw": function(expr) { - return [ "throw", walk(expr) ]; + return [ this[0], walk(expr) ]; }, "new": function(ctor, args) { - return [ "new", walk(ctor), MAP(args, walk) ]; + return [ this[0], walk(ctor), MAP(args, walk) ]; }, "switch": function(expr, body) { - return [ "switch", walk(expr), MAP(body, function(branch){ + return [ this[0], walk(expr), MAP(body, function(branch){ return [ branch[0] ? walk(branch[0]) : null, MAP(branch[1], walk) ]; }) ]; }, "break": function(label) { - return [ "break", label ]; + return [ this[0], label ]; }, "continue": function(label) { - return [ "continue", label ]; + return [ this[0], label ]; }, "conditional": function(cond, t, e) { - return [ "conditional", walk(cond), walk(t), walk(e) ]; + return [ this[0], walk(cond), walk(t), walk(e) ]; }, "assign": function(op, lvalue, rvalue) { - return [ "assign", op, walk(lvalue), walk(rvalue) ]; + return [ this[0], op, walk(lvalue), walk(rvalue) ]; }, "dot": function(expr) { - return [ "dot", walk(expr) ].concat(slice(arguments, 1)); + return [ this[0], walk(expr) ].concat(slice(arguments, 1)); }, "call": function(expr, args) { - return [ "call", walk(expr), MAP(args, walk) ]; + return [ this[0], walk(expr), MAP(args, walk) ]; }, "function": function(name, args, body) { - return [ "function", name, args.slice(), MAP(body, walk) ]; + return [ this[0], name, args.slice(), MAP(body, walk) ]; }, "defun": function(name, args, body) { - return [ "defun", name, args.slice(), MAP(body, walk) ]; + return [ this[0], name, args.slice(), MAP(body, walk) ]; }, "if": function(conditional, t, e) { - return [ "if", walk(conditional), walk(t), walk(e) ]; + return [ this[0], walk(conditional), walk(t), walk(e) ]; }, "for": function(init, cond, step, block) { - return [ "for", walk(init), walk(cond), walk(step), walk(block) ]; + return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; }, "for-in": function(has_var, key, hash, block) { - return [ "for-in", has_var, key, walk(hash), walk(block) ]; + return [ this[0], has_var, key, walk(hash), walk(block) ]; }, "while": function(cond, block) { - return [ "while", walk(cond), walk(block) ]; + return [ this[0], walk(cond), walk(block) ]; }, "do": function(cond, block) { - return [ "do", walk(cond), walk(block) ]; + return [ this[0], walk(cond), walk(block) ]; }, "return": function(expr) { - return [ "return", walk(expr) ]; + return [ this[0], walk(expr) ]; }, "binary": function(op, left, right) { - return [ "binary", op, walk(left), walk(right) ]; + return [ this[0], op, walk(left), walk(right) ]; }, "unary-prefix": function(op, expr) { - return [ "unary-prefix", op, walk(expr) ]; + return [ this[0], op, walk(expr) ]; }, "unary-postfix": function(op, expr) { - return [ "unary-postfix", op, walk(expr) ]; + return [ this[0], op, walk(expr) ]; }, "sub": function(expr, subscript) { - return [ "sub", walk(expr), walk(subscript) ]; + return [ this[0], walk(expr), walk(subscript) ]; }, "object": function(props) { - return [ "object", MAP(props, function(p){ + return [ this[0], MAP(props, function(p){ return p.length == 2 ? [ p[0], walk(p[1]) ] : [ p[0], walk(p[1]), p[2] ]; // get/set-ter }) ]; }, "regexp": function(rx, mods) { - return [ "regexp", rx, mods ]; + return [ this[0], rx, mods ]; }, "array": function(elements) { - return [ "array", MAP(elements, walk) ]; + return [ this[0], MAP(elements, walk) ]; }, "stat": function(stat) { - return [ "stat", walk(stat) ]; + return [ this[0], walk(stat) ]; }, "seq": function() { - return [ "seq" ].concat(MAP(slice(arguments), walk)); + return [ this[0] ].concat(MAP(slice(arguments), walk)); }, "label": function(name, block) { - return [ "label", name, walk(block) ]; + return [ this[0], name, walk(block) ]; }, "with": function(expr, block) { - return [ "with", walk(expr), walk(block) ]; + return [ this[0], walk(expr), walk(block) ]; }, "atom": function(name) { - return [ "atom", name ]; + return [ this[0], name ]; } }; @@ -405,7 +401,7 @@ function ast_add_scope(ast) { }, "try": function(t, c, f) { if (c != null) return [ - "try", + this[0], MAP(t, walk), [ define(c[0]), MAP(c[1], walk) ], f != null ? MAP(f, walk) : null @@ -491,9 +487,9 @@ function ast_mangle(ast, do_toplevel) { }; function _vardefs(defs) { - return MAP(defs, function(d){ + return [ this[0], MAP(defs, function(d){ return [ get_mangled(d[0]), walk(d[1]) ]; - }); + }) ]; }; return w.with_walkers({ @@ -510,28 +506,25 @@ function ast_mangle(ast, do_toplevel) { } return ast; }, - "var": function(defs) { - return [ "var", _vardefs(defs) ]; - }, - "const": function(defs) { - return [ "const", _vardefs(defs) ]; - }, + "var": _vardefs, + "const": _vardefs, "name": function(name) { - return [ "name", get_mangled(name) ]; + return [ this[0], get_mangled(name) ]; }, "try": function(t, c, f) { - return [ "try", + return [ this[0], MAP(t, walk), c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null, f != null ? MAP(f, walk) : null ]; }, "toplevel": function(body) { - return with_scope(this.scope, function(){ - return [ "toplevel", MAP(body, walk) ]; + var self = this; + return with_scope(self.scope, function(){ + return [ self[0], MAP(body, walk) ]; }); }, "for-in": function(has_var, name, obj, stat) { - return [ "for-in", has_var, get_mangled(name), walk(obj), walk(stat) ]; + return [ this[0], has_var, get_mangled(name), walk(obj), walk(stat) ]; } }, function() { return walk(ast_add_scope(ast)); @@ -569,28 +562,29 @@ function aborts(t) { } }; -function negate(c) { - var not_c = [ "unary-prefix", "!", c ]; - switch (c[0]) { - case "unary-prefix": - return c[1] == "!" ? c[2] : not_c; - case "binary": - var op = c[1], left = c[2], right = c[3]; - switch (op) { - case "<=": return [ "binary", ">", left, right ]; - case "<": return [ "binary", ">=", left, right ]; - case ">=": return [ "binary", "<", left, right ]; - case ">": return [ "binary", "<=", left, right ]; - case "==": return [ "binary", "!=", left, right ]; - case "!=": return [ "binary", "==", left, right ]; - case "===": return [ "binary", "!==", left, right ]; - case "!==": return [ "binary", "===", left, right ]; - case "&&": return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); - case "||": return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); - } - break; - } - return not_c; +function boolean_expr(expr) { + return ( (expr[0] == "unary-prefix" + && member(expr[1], [ "!", "delete" ])) || + + (expr[0] == "binary" + && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) || + + (expr[0] == "binary" + && member(expr[1], [ "&&", "||" ]) + && boolean_expr(expr[2]) + && boolean_expr(expr[3])) || + + (expr[0] == "conditional" + && boolean_expr(expr[2]) + && boolean_expr(expr[3])) || + + (expr[0] == "assign" + && expr[1] === true + && boolean_expr(expr[3])) || + + (expr[0] == "seq" + && boolean_expr(expr[expr.length - 1])) + ); }; function make_conditional(c, t, e) { @@ -609,12 +603,44 @@ function ast_squeeze(ast, options) { options = defaults(options, { make_seqs : true, dead_code : true, - no_warnings : false, - extra : false + keep_comps : true, + no_warnings : false }); var w = ast_walker(), walk = w.walk, scope; + function negate(c) { + var not_c = [ "unary-prefix", "!", c ]; + switch (c[0]) { + case "unary-prefix": + return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c; + case "seq": + c = slice(c); + c[c.length - 1] = negate(c[c.length - 1]); + return c; + case "conditional": + return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]); + case "binary": + var op = c[1], left = c[2], right = c[3]; + if (!options.keep_comps) switch (op) { + case "<=" : return [ "binary", ">", left, right ]; + case "<" : return [ "binary", ">=", left, right ]; + case ">=" : return [ "binary", "<", left, right ]; + case ">" : return [ "binary", "<=", left, right ]; + } + switch (op) { + case "==" : return [ "binary", "!=", left, right ]; + case "!=" : return [ "binary", "==", left, right ]; + case "===" : return [ "binary", "!==", left, right ]; + case "!==" : return [ "binary", "===", left, right ]; + case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); + case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); + } + break; + } + return not_c; + }; + function with_scope(s, cont) { var _scope = scope; scope = s; @@ -628,87 +654,12 @@ function ast_squeeze(ast, options) { return node[0] == "string" || node[0] == "num"; }; - function find_first_execute(node) { - if (!node) - return false; - - switch (node[0]) { - case "num": - case "string": - case "name": - return node; - case "call": - case "conditional": - case "for": - case "if": - case "new": - case "return": - case "stat": - case "switch": - case "throw": - return find_first_execute(node[1]); - case "binary": - return find_first_execute(node[2]); - case "assign": - if (node[1] === true) - return find_first_execute(node[3]); - break; - case "var": - if (node[1][0].length > 1) - return find_first_execute(node[1][0][1]); - break; - } - return null; - } - - function find_assign_recursive(p, v) { - if (p[0] == "assign" && p[1] != true || p[0] == "unary-prefix") { - if (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1]) - return true; - return false; - } - - if (p[0] != "assign" || p[1] !== true) - return false; - - if ((is_constant(p[3]) && p[3][0] == v[0] && p[3][1] == v[1]) || - (p[3][0] == "name" && v[0] == "name" && p[3][1] == v[1]) || - (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1])) - return true; - - return find_assign_recursive(p[3], v); - }; - function rmblock(block) { if (block != null && block[0] == "block" && block[1] && block[1].length == 1) block = block[1][0]; return block; }; - function clone(obj) { - if (obj && obj.constructor == Array) - return MAP(obj, clone); - return obj; - }; - - function make_seq_to_statements(node) { - if (node[0] != "seq") { - switch (node[0]) { - case "var": - case "const": - return [ node ]; - default: - return [ [ "stat", node ] ]; - } - } - - var ret = []; - for (var i = 1; i < node.length; i++) - ret.push.apply(ret, make_seq_to_statements(node[i])); - - return ret; - }; - function _lambda(name, args, body) { return [ this[0], name, args, with_scope(body.scope, function(){ return tighten(MAP(body, walk), "lambda"); @@ -734,64 +685,6 @@ function ast_squeeze(ast, options) { return a; }, []); - if (options.extra) { - // Detightening things. We do this because then we can assume that the - // statements are structured in a specific way. - statements = (function(a, prev) { - statements.forEach(function(cur) { - switch (cur[0]) { - case "for": - if (cur[1] != null) { - a.push.apply(a, make_seq_to_statements(cur[1])); - cur[1] = null; - } - a.push(cur); - break; - case "stat": - var stats = make_seq_to_statements(cur[1]); - stats.forEach(function(s) { - if (s[1][0] == "unary-postfix") - s[1][0] = "unary-prefix"; - }); - a.push.apply(a, stats); - break; - default: - a.push(cur); - } - }); - return a; - })([]); - - statements = (function(a, prev) { - statements.forEach(function(cur) { - if (!(prev && prev[0] == "stat")) { - a.push(cur); - prev = cur; - return; - } - - var p = prev[1]; - var c = find_first_execute(cur); - if (c && find_assign_recursive(p, c)) { - var old_cur = clone(cur); - c.splice(0, c.length); - c.push.apply(c, p); - var tmp_cur = best_of(cur, [ "toplevel", [ prev, old_cur ] ]); - if (tmp_cur == cur) { - a[a.length -1] = cur; - } else { - cur = old_cur; - a.push(cur); - } - } else { - a.push(cur); - } - prev = cur; - }); - return a; - })([]); - } - statements = (function(a, prev){ statements.forEach(function(cur){ if (prev && ((cur[0] == "var" && prev[0] == "var") || @@ -835,22 +728,6 @@ function ast_squeeze(ast, options) { return a; })([]); - if (options.extra) { - statements = (function(a, prev){ - statements.forEach(function(cur){ - var replaced = false; - if (prev && cur[0] == "for" && cur[1] == null && (prev[0] == "var" || prev[0] == "const" || prev[0] == "stat")) { - cur[1] = prev; - a[a.length - 1] = cur; - } else { - a.push(cur); - } - prev = cur; - }); - return a; - })([]); - } - if (block_type == "lambda") statements = (function(i, a, stat){ while (i < statements.length) { stat = statements[i++]; @@ -901,7 +778,10 @@ function ast_squeeze(ast, options) { if (empty(e) && empty(t)) return [ "stat", c ]; var ret = [ "if", c, t, e ]; - if (t[0] == "stat") { + if (t[0] == "if" && empty(t[3]) && empty(e)) { + ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ])); + } + else if (t[0] == "stat") { if (e) { if (e[0] == "stat") { ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]); @@ -972,23 +852,34 @@ function ast_squeeze(ast, options) { left = walk(left); right = walk(right); var best = [ "binary", op, left, right ]; - if (is_constant(right)) { - if (is_constant(left)) { - var val = null; - switch (op) { - case "+": val = left[1] + right[1]; break; - case "*": val = left[1] * right[1]; break; - case "/": val = left[1] / right[1]; break; - case "-": val = left[1] - right[1]; break; - case "<<": val = left[1] << right[1]; break; - case ">>": val = left[1] >> right[1]; break; - case ">>>": val = left[1] >>> right[1]; break; - } - if (val != null) { - best = best_of(best, [ typeof val == "string" ? "string" : "num", val ]); + if (is_constant(right) && is_constant(left)) { + var val = {}; + var orig = val; + switch (op) { + case "+" : val = left[1] + right[1]; break; + case "*" : val = left[1] * right[1]; break; + case "/" : val = left[1] / right[1]; break; + case "-" : val = left[1] - right[1]; break; + case "<<" : val = left[1] << right[1]; break; + case ">>" : val = left[1] >> right[1]; break; + case ">>>" : val = left[1] >>> right[1]; break; + case "==" : val = left[1] == right[1]; break; + case "===" : val = left[1] === right[1]; break; + case "!=" : val = left[1] != right[1]; break; + case "!==" : val = left[1] !== right[1]; break; + case "<" : val = left[1] < right[1]; break; + case "<=" : val = left[1] <= right[1]; break; + case ">" : val = left[1] > right[1]; break; + case ">=" : val = left[1] >= right[1]; break; + } + if (val !== orig) { + switch (typeof val) { + case "string": val = [ "string", val ]; break; + case "boolean": val = [ "name", val+"" ]; break; + case "number": val = [ "num", val ]; break; + default: return best; } - } else if (left[0] == "binary" && left[1] == "+" && left[3][0] == "string") { - best = best_of(best, [ "binary", "+", left[2], [ "string", left[3][1] + right[1] ] ]); + best = best_of(best, walk(val)); } } return best; @@ -1004,17 +895,12 @@ function ast_squeeze(ast, options) { f != null ? tighten(MAP(f, walk)) : null ]; }, - "unary-prefix": function(op, cond) { - if (op == "!") { - cond = walk(cond); - if (cond[0] == "unary-prefix" && cond[1] == "!") { - var p = w.parent(); - if (p[0] == "unary-prefix" && p[1] == "!") - return cond[2]; - return [ "unary-prefix", "!", cond ]; - } - return best_of(this, negate(cond)); - } + "unary-prefix": function(op, expr) { + expr = walk(expr); + var ret = [ "unary-prefix", op, expr ]; + if (op == "!") + ret = best_of(ret, negate(expr)); + return ret; }, "name": function(name) { switch (name) { @@ -1253,7 +1139,9 @@ function gen_code(ast, beautify) { }, "dot": function(expr) { var out = make(expr), i = 1; - if (needs_parens(expr)) + if (expr[0] == "num") + out += "."; + else if (needs_parens(expr)) out = "(" + out + ")"; while (i < arguments.length) out += "." + make_name(arguments[i++]); @@ -1314,7 +1202,8 @@ function gen_code(ast, beautify) { left = "(" + left + ")"; } if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || - rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]]) { + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && + !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { right = "(" + right + ")"; } return add_spaces([ left, operator, right ]); @@ -1350,7 +1239,8 @@ function gen_code(ast, beautify) { var key = p[0], val = make(p[1]); if (beautify && beautify.quote_keys) { key = make_string(key); - } else if (typeof key == "number" || !beautify && +key + "" == key) { + } else if ((typeof key == "number" || !beautify && +key + "" == key) + && parseFloat(key) >= 0) { key = make_num(+key); } else if (!is_identifier(key)) { key = make_string(key); @@ -1367,6 +1257,7 @@ function gen_code(ast, beautify) { "array": function(elements) { if (elements.length == 0) return "[]"; return add_spaces([ "[", add_commas(MAP(elements, function(el){ + if (!beautify && el[0] == "atom" && el[1] == "undefined") return ""; return parenthesize(el, "seq"); })), "]" ]); }, @@ -1384,12 +1275,6 @@ function gen_code(ast, beautify) { }, "atom": function(name) { return make_name(name); - }, - "comment1": function(text) { - return "//" + text + "\n"; - }, - "comment2": function(text) { - return "/*" + text + "*/"; } }; @@ -1442,8 +1327,16 @@ function gen_code(ast, beautify) { var stat = statements[i]; var code = make(stat); if (code != ";") { - if (!beautify && i == last) - code = code.replace(/;+\s*$/, ""); + if (!beautify && i == last) { + if ((stat[0] == "while" && empty(stat[2])) || + (member(stat[0], [ "for", "for-in"] ) && empty(stat[4])) || + (stat[0] == "if" && empty(stat[2]) && !stat[3]) || + (stat[0] == "if" && stat[3] && empty(stat[3]))) { + code = code.replace(/;*\s*$/, ";"); + } else { + code = code.replace(/;+\s*$/, ""); + } + } a.push(code); } } @@ -1498,6 +1391,49 @@ function gen_code(ast, beautify) { return make(ast); }; +function split_lines(code, max_line_length) { + var splits = [ 0 ]; + jsp.parse(function(){ + var next_token = jsp.tokenizer(code); + var last_split = 0; + var prev_token; + function current_length(tok) { + return tok.pos - last_split; + }; + function split_here(tok) { + last_split = tok.pos; + splits.push(last_split); + }; + function custom(){ + var tok = next_token.apply(this, arguments); + out: { + if (prev_token) { + if (prev_token.type == "keyword") break out; + } + if (current_length(tok) > max_line_length) { + switch (tok.type) { + case "keyword": + case "atom": + case "name": + case "punc": + split_here(tok); + break out; + } + } + } + prev_token = tok; + return tok; + }; + custom.context = function() { + return next_token.context.apply(this, arguments); + }; + return custom; + }()); + return splits.map(function(pos, i){ + return code.substring(pos, splits[i + 1] || code.length); + }).join("\n"); +}; + /* -----[ Utilities ]----- */ function repeat_string(str, i) { @@ -1558,3 +1494,5 @@ exports.gen_code = gen_code; exports.ast_add_scope = ast_add_scope; exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; exports.set_logger = function(logger) { warn = logger }; +exports.make_string = make_string; +exports.split_lines = split_lines; diff --git a/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js b/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js index a01046b..a6f59ca 100644 --- a/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js +++ b/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js @@ -139,7 +139,7 @@ WebInspector.WatchExpressionsSection.prototype = { if (!expression) continue; - WebInspector.console.evalInInspectedWindow("(" + expression + ")", this._watchObjectGroupId, appendResult.bind(this, expression, i)); + WebInspector.console.evalInInspectedWindow("(" + expression + ")", this._watchObjectGroupId, false, appendResult.bind(this, expression, i)); } // note this is setting the expansion of the tree, not the section; diff --git a/Source/WebCore/inspector/front-end/WebKit.qrc b/Source/WebCore/inspector/front-end/WebKit.qrc index edc1861..dd325ba 100644 --- a/Source/WebCore/inspector/front-end/WebKit.qrc +++ b/Source/WebCore/inspector/front-end/WebKit.qrc @@ -13,7 +13,6 @@ <file>BreakpointManager.js</file> <file>BreakpointsSidebarPane.js</file> <file>CallStackSidebarPane.js</file> - <file>ChangesView.js</file> <file>Checkbox.js</file> <file>Color.js</file> <file>ConsolePanel.js</file> @@ -28,6 +27,7 @@ <file>Database.js</file> <file>DatabaseQueryView.js</file> <file>DatabaseTableView.js</file> + <file>DetailedHeapshotView.js</file> <file>DataGrid.js</file> <file>DebuggerModel.js</file> <file>DOMAgent.js</file> @@ -44,10 +44,10 @@ <file>ExtensionPanel.js</file> <file>ExtensionRegistryStub.js</file> <file>ExtensionServer.js</file> - <file>FileSystemView.js</file> <file>FontView.js</file> <file>GoToLineDialog.js</file> <file>HAREntry.js</file> + <file>HeapSnapshot.js</file> <file>HeapSnapshotView.js</file> <file>HelpScreen.js</file> <file>ImageView.js</file> @@ -64,6 +64,7 @@ <file>Panel.js</file> <file>PanelEnablerView.js</file> <file>Placard.js</file> + <file>PleaseWaitMessage.js</file> <file>Popover.js</file> <file>ProfileDataGridTree.js</file> <file>ProfilesPanel.js</file> @@ -84,18 +85,18 @@ <file>ScriptFormatter.js</file> <file>ScriptFormatterWorker.js</file> <file>ScriptsPanel.js</file> - <file>ScriptView.js</file> <file>Section.js</file> <file>Settings.js</file> <file>ShortcutsHelp.js</file> + <file>ShowMoreDataGridNode.js</file> <file>SidebarPane.js</file> <file>SidebarTreeElement.js</file> <file>SourceCSSTokenizer.js</file> <file>SourceFrame.js</file> + <file>SourceFrameContent.js</file> <file>SourceHTMLTokenizer.js</file> <file>SourceJavaScriptTokenizer.js</file> <file>SourceTokenizer.js</file> - <file>SourceView.js</file> <file>StatusBarButton.js</file> <file>StylesSidebarPane.js</file> <file>SummaryBar.js</file> diff --git a/Source/WebCore/inspector/front-end/inspector.css b/Source/WebCore/inspector/front-end/inspector.css index f629d12..c992806 100644 --- a/Source/WebCore/inspector/front-end/inspector.css +++ b/Source/WebCore/inspector/front-end/inspector.css @@ -428,10 +428,6 @@ body.port-qt #dock-status-bar-item { -webkit-mask-image: url(Images/clearConsoleButtonGlyph.png); } -#changes-status-bar-item .glyph { - -webkit-mask-image: url(Images/consoleButtonGlyph.png); /* TODO: Needs Image for Changes Toggle Button */ -} - #counters { position: absolute; right: 16px; @@ -442,22 +438,14 @@ body.port-qt #dock-status-bar-item { height: 19px; } -#changes-count, #error-warning-count { +#error-warning-count { display: inline; } -#error-warning-count:hover, #changes-count:hover { +#error-warning-count:hover { border-bottom: 1px solid rgb(96, 96, 96); } -#style-changes-count::before { - content: url(Images/styleIcon.png); /* TODO: Needs Image for Style Changes Icon */ - width: 10px; - height: 10px; - vertical-align: -1px; - margin-right: 2px; -} - #error-count::before { content: url(Images/errorIcon.png); width: 10px; @@ -466,7 +454,7 @@ body.port-qt #dock-status-bar-item { margin-right: 2px; } -#changes-count + #error-warning-count, #error-count + #warning-count { +#error-count + #warning-count { margin-left: 6px; } @@ -685,6 +673,7 @@ body.platform-linux .monospace, body.platform-linux .source-code { .console-message-url { float: right; + margin-left: 4px; } .console-group-messages .section { @@ -2096,6 +2085,10 @@ li.selected .base-storage-tree-element-subtitle { content: url(Images/treeDownTriangleBlack.png); } +.data-grid button { + line-height: 19px; +} + body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-descending { background-image: url(Images/glossyHeader.png); border-right: 1px solid rgb(179, 179, 179); @@ -4320,3 +4313,17 @@ a.worker-item:hover { .cursor-auto { cursor: auto; } + +.please-wait-msg { + position: absolute; + left: 0; + top: 0; + border: 4px black solid; + border-radius: 4px; + background-color: black; + opacity: 0.85; + color: white; + font-size: 12px; + font-weight: bold; + z-index: 10000; +} diff --git a/Source/WebCore/inspector/front-end/inspector.html b/Source/WebCore/inspector/front-end/inspector.html index 0e0b9e9..0435dc3 100644 --- a/Source/WebCore/inspector/front-end/inspector.html +++ b/Source/WebCore/inspector/front-end/inspector.html @@ -54,9 +54,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="Popover.js"></script> <script type="text/javascript" src="TabbedPane.js"></script> <script type="text/javascript" src="Placard.js"></script> + <script type="text/javascript" src="PleaseWaitMessage.js"></script> <script type="text/javascript" src="View.js"></script> <script type="text/javascript" src="Drawer.js"></script> - <script type="text/javascript" src="ChangesView.js"></script> <script type="text/javascript" src="ConsoleView.js"></script> <script type="text/javascript" src="Panel.js"></script> <script type="text/javascript" src="TimelineGrid.js"></script> @@ -68,10 +68,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="DOMStorage.js"></script> <script type="text/javascript" src="DOMStorageItemsView.js"></script> <script type="text/javascript" src="DataGrid.js"></script> + <script type="text/javascript" src="ShowMoreDataGridNode.js"></script> <script type="text/javascript" src="CookiesTable.js"></script> <script type="text/javascript" src="CookieItemsView.js"></script> <script type="text/javascript" src="ApplicationCacheItemsView.js"></script> - <script type="text/javascript" src="FileSystemView.js"></script> <script type="text/javascript" src="Script.js"></script> <script type="text/javascript" src="Breakpoint.js"></script> <script type="text/javascript" src="BreakpointManager.js"></script> @@ -101,6 +101,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="ElementsPanel.js"></script> <script type="text/javascript" src="NetworkPanel.js"></script> <script type="text/javascript" src="InjectedFakeWorker.js"></script> + <script type="text/javascript" src="SourceFrame.js"></script> + <script type="text/javascript" src="SourceFrameContent.js"></script> + <script type="text/javascript" src="ResourceView.js"></script> <script type="text/javascript" src="ScriptsPanel.js"></script> <script type="text/javascript" src="ResourcesPanel.js"></script> <script type="text/javascript" src="ProfilesPanel.js"></script> @@ -120,8 +123,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="ResourceCookiesView.js"></script> <script type="text/javascript" src="ResourceTimingView.js"></script> <script type="text/javascript" src="NetworkItemView.js"></script> - <script type="text/javascript" src="ResourceView.js"></script> - <script type="text/javascript" src="SourceFrame.js"></script> <script type="text/javascript" src="ScriptFormatter.js"></script> <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script> <script type="text/javascript" src="TextEditorModel.js"></script> @@ -131,17 +132,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="SourceCSSTokenizer.js"></script> <script type="text/javascript" src="SourceHTMLTokenizer.js"></script> <script type="text/javascript" src="SourceJavaScriptTokenizer.js"></script> - <script type="text/javascript" src="SourceView.js"></script> <script type="text/javascript" src="FontView.js"></script> <script type="text/javascript" src="ImageView.js"></script> <script type="text/javascript" src="DatabaseTableView.js"></script> <script type="text/javascript" src="DatabaseQueryView.js"></script> - <script type="text/javascript" src="ScriptView.js"></script> <script type="text/javascript" src="ProfileDataGridTree.js"></script> <script type="text/javascript" src="BottomUpProfileDataGridTree.js"></script> <script type="text/javascript" src="TopDownProfileDataGridTree.js"></script> <script type="text/javascript" src="ProfileView.js"></script> + <script type="text/javascript" src="HeapSnapshot.js"></script> <script type="text/javascript" src="HeapSnapshotView.js"></script> + <script type="text/javascript" src="DetailedHeapshotView.js"></script> <script type="text/javascript" src="DebuggerModel.js"></script> <script type="text/javascript" src="DOMAgent.js"></script> <script type="text/javascript" src="TimelineAgent.js"></script> @@ -164,7 +165,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. </div> <div id="main"> <div id="main-panels" spellcheck="false"></div> - <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="changes-status-bar-item" class="status-bar-item hidden"></button><div id="counters"><div id="changes-count" class="hidden"></div><div id="error-warning-count" class="hidden"></div></div></div></div> + <div id="main-status-bar" class="status-bar"><div id="anchored-status-bar-items"><button id="dock-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><button id="console-status-bar-item" class="status-bar-item"><div class="glyph"></div><div class="glyph shadow"></div></button><div id="counters"><div id="error-warning-count" class="hidden"></div></div></div></div> </div> <div id="drawer"> <div id="console-view"><div id="console-messages" class="monospace"><div id="console-prompt" spellcheck="false"><br></div></div></div> diff --git a/Source/WebCore/inspector/front-end/inspector.js b/Source/WebCore/inspector/front-end/inspector.js index 77abe78..0959289 100644 --- a/Source/WebCore/inspector/front-end/inspector.js +++ b/Source/WebCore/inspector/front-end/inspector.js @@ -223,8 +223,12 @@ var WebInspector = { if (hiddenPanels.indexOf("profiles") === -1) { this.panels.profiles = new WebInspector.ProfilesPanel(); this.panels.profiles.registerProfileType(new WebInspector.CPUProfileType()); - if (Preferences.heapProfilerPresent) - this.panels.profiles.registerProfileType(new WebInspector.HeapSnapshotProfileType()); + if (Preferences.heapProfilerPresent) { + if (!Preferences.detailedHeapProfiles) + this.panels.profiles.registerProfileType(new WebInspector.HeapSnapshotProfileType()); + else + this.panels.profiles.registerProfileType(new WebInspector.DetailedHeapshotProfileType()); + } } if (hiddenPanels.indexOf("audits") === -1) this.panels.audits = new WebInspector.AuditsPanel(); @@ -344,53 +348,6 @@ var WebInspector = { errorWarningElement.title = null; }, - get styleChanges() - { - return this._styleChanges; - }, - - set styleChanges(x) - { - x = Math.max(x, 0); - - if (this._styleChanges === x) - return; - this._styleChanges = x; - this._updateChangesCount(); - }, - - _updateChangesCount: function() - { - // TODO: Remove immediate return when enabling the Changes Panel - return; - - var changesElement = document.getElementById("changes-count"); - if (!changesElement) - return; - - if (!this.styleChanges) { - changesElement.addStyleClass("hidden"); - return; - } - - changesElement.removeStyleClass("hidden"); - changesElement.removeChildren(); - - if (this.styleChanges) { - var styleChangesElement = document.createElement("span"); - styleChangesElement.id = "style-changes-count"; - styleChangesElement.textContent = this.styleChanges; - changesElement.appendChild(styleChangesElement); - } - - if (this.styleChanges) { - if (this.styleChanges === 1) - changesElement.title = WebInspector.UIString("%d style change", this.styleChanges); - else - changesElement.title = WebInspector.UIString("%d style changes", this.styleChanges); - } - }, - highlightDOMNode: function(nodeId) { if ("_hideDOMNodeHighlightTimeout" in this) { @@ -445,6 +402,11 @@ var WebInspector = { resourceForURL: function(url) { return this.resourceTreeModel.resourceForURL(url); + }, + + openLinkExternallyLabel: function() + { + return WebInspector.UIString("Open Link in New Window"); } } @@ -471,7 +433,9 @@ WebInspector.PlatformFlavor = { WebInspector.loaded = function() { if ("page" in WebInspector.queryParamsObject) { - WebInspector.socket = new WebSocket("ws://" + window.location.host + "/devtools/page/" + WebInspector.queryParamsObject.page); + var page = WebInspector.queryParamsObject.page; + var host = "host" in WebInspector.queryParamsObject ? WebInspector.queryParamsObject.host : window.location.host; + WebInspector.socket = new WebSocket("ws://" + host + "/devtools/page/" + page); WebInspector.socket.onmessage = function(message) { InspectorBackend.dispatch(message.data); } WebInspector.socket.onerror = function(error) { console.error(error); } WebInspector.socket.onopen = function() { @@ -506,9 +470,6 @@ WebInspector.doLoadedDone = function() this.drawer = new WebInspector.Drawer(); this.console = new WebInspector.ConsoleView(this.drawer); - // TODO: Uncomment when enabling the Changes Panel - // this.changes = new WebInspector.ChangesView(this.drawer); - // TODO: Remove class="hidden" from inspector.html on button#changes-status-bar-item this.drawer.visibleView = this.console; this.resourceTreeModel = new WebInspector.ResourceTreeModel(); this.networkManager = new WebInspector.NetworkManager(this.resourceTreeModel); @@ -573,12 +534,6 @@ WebInspector.doLoadedDone = function() errorWarningCount.addEventListener("click", this.showConsole.bind(this), false); this._updateErrorAndWarningCounts(); - this.styleChanges = 0; - // TODO: Uncomment when enabling the Changes Panel - // var changesElement = document.getElementById("changes-count"); - // changesElement.addEventListener("click", this.showChanges.bind(this), false); - // this._updateErrorAndWarningCounts(); - var searchField = document.getElementById("search"); searchField.addEventListener("search", this.performSearch.bind(this), false); // when the search is emptied searchField.addEventListener("mousedown", this._searchFieldManualFocus.bind(this), false); // when the search field is manually selected @@ -597,6 +552,13 @@ WebInspector.doLoadedDone = function() } InspectorBackend.populateScriptObjects(onPopulateScriptObjects); + if (Preferences.debuggerAlwaysEnabled || WebInspector.settings.debuggerEnabled) + this.debuggerModel.enableDebugger(); + if (Preferences.profilerAlwaysEnabled || WebInspector.settings.profilerEnabled) + InspectorBackend.enableProfiler(); + if (WebInspector.settings.monitoringXHREnabled) + InspectorBackend.setMonitoringXHREnabled(true); + InspectorBackend.setConsoleMessagesEnabled(true); function propertyNamesCallback(names) @@ -913,13 +875,13 @@ WebInspector.documentKeyDown = function(event) case "U+0052": // R key if ((event.metaKey && isMac) || (event.ctrlKey && !isMac)) { - InspectorBackend.reloadPage(); + InspectorBackend.reloadPage(event.shiftKey); event.preventDefault(); } break; case "F5": if (!isMac) - InspectorBackend.reloadPage(); + InspectorBackend.reloadPage(event.ctrlKey || event.shiftKey); break; } } @@ -946,6 +908,7 @@ WebInspector.animateStyle = function(animations, duration, callback) { var interval; var complete = 0; + var hasCompleted = false; const intervalDuration = (1000 / 30); // 30 frames per second. const animationsLength = animations.length; @@ -1014,14 +977,32 @@ WebInspector.animateStyle = function(animations, duration, callback) // End condition. if (complete >= duration) { + hasCompleted = true; clearInterval(interval); if (callback) callback(); } } + function forceComplete() + { + if (!hasCompleted) { + complete = duration; + animateLoop(); + } + } + + function cancel() + { + hasCompleted = true; + clearInterval(interval); + } + interval = setInterval(animateLoop, intervalDuration); - return interval; + return { + cancel: cancel, + forceComplete: forceComplete + }; } WebInspector.updateSearchLabel = function() @@ -1147,11 +1128,6 @@ WebInspector.showConsole = function() this.drawer.showView(this.console); } -WebInspector.showChanges = function() -{ - this.drawer.showView(this.changes); -} - WebInspector.showPanel = function(panel) { if (!(panel in this.panels)) @@ -1171,8 +1147,8 @@ WebInspector.domContentEventFired = function(time) WebInspector.loadEventFired = function(time) { this.panels.audits.mainResourceLoadTime = time; - if (this.panels.network) - this.panels.network.mainResourceLoadTime = time; + this.panels.network.mainResourceLoadTime = time; + this.panels.resources.loadEventFired(); this.extensionServer.notifyPageLoaded((time - WebInspector.mainResource.startTime) * 1000); this.mainResourceLoadTime = time; } @@ -1381,6 +1357,8 @@ WebInspector.showSourceLine = function(url, line, preferredPanel) this.currentPanel = this._choosePanelToShowSourceLine(url, line, preferredPanel); if (!this.currentPanel) return false; + if (this.drawer) + this.drawer.immediatelyFinishAnimation(); this.currentPanel.showSourceLine(url, line); return true; } @@ -1511,7 +1489,19 @@ WebInspector.completeURL = function(baseURL, href) var path = href; if (path.charAt(0) !== "/") { var basePath = parsedURL.path; - path = basePath.substring(0, basePath.lastIndexOf("/")) + "/" + path; + // A href of "?foo=bar" implies "basePath?foo=bar". + // With "basePath?a=b" and "?foo=bar" we should get "basePath?foo=bar". + var prefix; + if (path.charAt(0) === "?") { + var basePathCutIndex = basePath.indexOf("?"); + if (basePathCutIndex !== -1) + prefix = basePath.substring(0, basePathCutIndex); + else + prefix = basePath; + } else + prefix = basePath.substring(0, basePath.lastIndexOf("/")) + "/"; + + path = prefix + path; } else if (path.length > 1 && path.charAt(1) === "/") { // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol). return parsedURL.scheme + ":" + path; @@ -1576,6 +1566,12 @@ WebInspector.performSearch = function(event) this.doPerformSearch(event.target.value, forceSearch, event.shiftKey, false); } +WebInspector.cancelSearch = function() +{ + document.getElementById("search").value = ""; + this.doPerformSearch(""); +} + WebInspector.doPerformSearch = function(query, forceSearch, isBackwardSearch, repeatSearch) { var isShortSearch = (query.length < 3); @@ -1873,6 +1869,7 @@ WebInspector.MIMETypes = { "font/opentype": {3: true}, "application/x-font-type1": {3: true}, "application/x-font-ttf": {3: true}, + "application/x-font-woff": {3: true}, "application/x-truetype-font": {3: true}, "text/javascript": {4: true}, "text/ecmascript": {4: true}, diff --git a/Source/WebCore/inspector/front-end/networkPanel.css b/Source/WebCore/inspector/front-end/networkPanel.css index 95ed1bf..c750323 100644 --- a/Source/WebCore/inspector/front-end/networkPanel.css +++ b/Source/WebCore/inspector/front-end/networkPanel.css @@ -65,6 +65,18 @@ font-weight: bold; } +.network-sidebar .data-grid.small tr.offscreen { + height: 21px; +} + +.network-sidebar .data-grid tr.offscreen { + height: 41px; +} + +.network-sidebar .data-grid tr.offscreen td { + display: none; +} + .network-sidebar .data-grid tr.filler { background-color: white; } diff --git a/Source/WebCore/inspector/front-end/textViewer.css b/Source/WebCore/inspector/front-end/textViewer.css index bee9fe5..f6aa65e 100644 --- a/Source/WebCore/inspector/front-end/textViewer.css +++ b/Source/WebCore/inspector/front-end/textViewer.css @@ -9,12 +9,34 @@ } .text-editor-lines { - border: 0; - -webkit-border-horizontal-spacing: 0; - -webkit-border-vertical-spacing: 0; + position: absolute; + top: 0; + left: 0; + bottom: 0; + overflow: hidden; + -webkit-user-select: none; +} + +.text-editor-contents { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: auto; -webkit-user-select: text; } +.text-editor-editable { + -webkit-user-modify: read-write-plaintext-only; +} + +.webkit-line-decorations { + pointer-events: none; + -webkit-user-select: none; + -webkit-user-modify: read-only; +} + .webkit-html-message-bubble { -webkit-box-shadow: black 0px 2px 5px; -webkit-border-radius: 9px; @@ -63,7 +85,6 @@ text-align: right; vertical-align: top; word-break: normal; - -webkit-user-select: none; padding-right: 4px; padding-left: 6px; } @@ -86,9 +107,7 @@ } .webkit-line-content { - width: 100%; padding-left: 2px; - vertical-align: top; } .webkit-breakpoint .webkit-line-number-outer { @@ -136,21 +155,21 @@ opacity: 0.3; } -.webkit-execution-line .webkit-line-content { +.webkit-execution-line.webkit-line-content { background-color: rgb(171, 191, 254); outline: 1px solid rgb(64, 115, 244); } -.diff-container .webkit-added-line .webkit-line-content { +.diff-container .webkit-added-line.webkit-line-content { background-color: rgb(220, 255, 220); } -.diff-container .webkit-removed-line .webkit-line-content { +.diff-container .webkit-removed-line.webkit-line-content { background-color: rgb(255, 220, 220); text-decoration: line-through; } -.diff-container .webkit-changed-line .webkit-line-content { +.diff-container .webkit-changed-line.webkit-line-content { background-color: rgb(220, 220, 255); } @@ -164,7 +183,7 @@ color: black; } -.webkit-highlighted-line .webkit-line-content { +.webkit-highlighted-line.webkit-line-content { -webkit-animation: "fadeout" 2s 0s; } |