summaryrefslogtreecommitdiffstats
path: root/WebCore/inspector/front-end
diff options
context:
space:
mode:
authorFeng Qian <fqian@google.com>2009-06-17 12:12:20 -0700
committerFeng Qian <fqian@google.com>2009-06-17 12:12:20 -0700
commit5f1ab04193ad0130ca8204aadaceae083aca9881 (patch)
tree5a92cd389e2cfe7fb67197ce14b38469462379f8 /WebCore/inspector/front-end
parent194315e5a908cc8ed67d597010544803eef1ac59 (diff)
downloadexternal_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.zip
external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.tar.gz
external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.tar.bz2
Get WebKit r44544.
Diffstat (limited to 'WebCore/inspector/front-end')
-rw-r--r--WebCore/inspector/front-end/BottomUpProfileDataGridTree.js252
-rw-r--r--WebCore/inspector/front-end/Console.js49
-rw-r--r--WebCore/inspector/front-end/DataGrid.js79
-rw-r--r--WebCore/inspector/front-end/ElementsTreeOutline.js4
-rw-r--r--WebCore/inspector/front-end/Images/radioDot.pngbin0 -> 235 bytes
-rw-r--r--WebCore/inspector/front-end/PanelEnablerView.js21
-rw-r--r--WebCore/inspector/front-end/ProfileDataGridTree.js398
-rw-r--r--WebCore/inspector/front-end/ProfileView.js382
-rw-r--r--WebCore/inspector/front-end/ProfilesPanel.js16
-rw-r--r--WebCore/inspector/front-end/ResourcesPanel.js59
-rw-r--r--WebCore/inspector/front-end/ScriptsPanel.js60
-rw-r--r--WebCore/inspector/front-end/SourceFrame.js29
-rw-r--r--WebCore/inspector/front-end/SourceView.js13
-rw-r--r--WebCore/inspector/front-end/StylesSidebarPane.js4
-rw-r--r--WebCore/inspector/front-end/TopDownProfileDataGridTree.js111
-rw-r--r--WebCore/inspector/front-end/WebKit.qrc5
-rw-r--r--WebCore/inspector/front-end/inspector.css37
-rw-r--r--WebCore/inspector/front-end/inspector.html3
-rw-r--r--WebCore/inspector/front-end/inspector.js145
-rw-r--r--WebCore/inspector/front-end/utilities.js5
20 files changed, 1349 insertions, 323 deletions
diff --git a/WebCore/inspector/front-end/BottomUpProfileDataGridTree.js b/WebCore/inspector/front-end/BottomUpProfileDataGridTree.js
new file mode 100644
index 0000000..89b4ddc
--- /dev/null
+++ b/WebCore/inspector/front-end/BottomUpProfileDataGridTree.js
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2009 280 North 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.
+ */
+
+// Bottom Up Profiling shows the entire callstack backwards:
+// The root node is a representation of each individual function called, and each child of that node represents
+// a reverse-callstack showing how many of those calls came from it. So, unlike top-down, the statistics in
+// each child still represent the root node. We have to be particularly careful of recursion with this mode
+// because a root node can represent itself AND an ancestor.
+
+WebInspector.BottomUpProfileDataGridTree = function(/*ProfileView*/ aProfileView, /*ProfileNode*/ aProfileNode)
+{
+ WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode);
+
+ // Iterate each node in pre-order.
+ var profileNodeUIDs = 0;
+ var profileNodeGroups = [[], [aProfileNode]];
+ var visitedProfileNodesForCallUID = {};
+
+ this._remainingNodeInfos = [];
+
+ for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
+ var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
+ var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
+ var count = profileNodes.length;
+
+ for (var index = 0; index < count; ++index) {
+ var profileNode = profileNodes[index];
+
+ if (!profileNode.UID)
+ profileNode.UID = ++profileNodeUIDs;
+
+ if (profileNode.head && profileNode !== profileNode.head) {
+ // The total time of this ancestor is accounted for if we're in any form of recursive cycle.
+ var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
+ var totalTimeAccountedFor = false;
+
+ if (!visitedNodes) {
+ visitedNodes = {}
+ visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
+ } else {
+ // The total time for this node has already been accounted for iff one of it's parents has already been visited.
+ // We can do this check in this style because we are traversing the tree in pre-order.
+ var parentCount = parentProfileNodes.length;
+ for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
+ if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
+ totalTimeAccountedFor = true;
+ break;
+ }
+ }
+ }
+
+ visitedNodes[profileNode.UID] = true;
+
+ this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor });
+ }
+
+ var children = profileNode.children;
+ if (children.length) {
+ profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
+ profileNodeGroups.push(children);
+ }
+ }
+ }
+
+ // Populate the top level nodes.
+ WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(this);
+
+ return this;
+}
+
+WebInspector.BottomUpProfileDataGridTree.prototype = {
+ // When focusing, we keep the entire callstack up to this ancestor.
+ focus: function(/*ProfileDataGridNode*/ profileDataGridNode)
+ {
+ if (!profileDataGridNode)
+ return;
+
+ this._save();
+
+ var currentNode = profileDataGridNode;
+ var focusNode = profileDataGridNode;
+
+ while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
+ currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
+
+ focusNode = currentNode;
+ currentNode = currentNode.parent;
+
+ if (currentNode instanceof WebInspector.ProfileDataGridNode)
+ currentNode._keepOnlyChild(focusNode);
+ }
+
+ this.children = [focusNode];
+ this.totalTime = profileDataGridNode.totalTime;
+ },
+
+ exclude: function(/*ProfileDataGridNode*/ profileDataGridNode)
+ {
+ if (!profileDataGridNode)
+ return;
+
+ this._save();
+
+ var excludedCallUID = profileDataGridNode.callUID;
+ var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
+
+ // If we have a top level node that is excluded, get rid of it completely (not keeping children),
+ // since bottom up data relies entirely on the root node.
+ if (excludedTopLevelChild)
+ this.children.remove(excludedTopLevelChild);
+
+ var children = this.children;
+ var count = children.length;
+
+ for (var index = 0; index < count; ++index)
+ children[index]._exclude(excludedCallUID);
+
+ if (this.lastComparator)
+ this.sort(this.lastComparator, true);
+ }
+}
+
+WebInspector.BottomUpProfileDataGridTree.prototype.__proto__ = WebInspector.ProfileDataGridTree.prototype;
+
+WebInspector.BottomUpProfileDataGridNode = function(/*ProfileView*/ profileView, /*ProfileNode*/ profileNode, /*BottomUpProfileDataGridTree*/ owningTree)
+{
+ // In bottom up mode, our parents are our children since we display an inverted tree.
+ // However, we don't want to show the very top parent since it is redundant.
+ var hasChildren = !!(profileNode.parent && profileNode.parent.parent);
+
+ WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, hasChildren);
+
+ this._remainingNodeInfos = [];
+}
+
+WebInspector.BottomUpProfileDataGridNode.prototype = {
+ _takePropertiesFromProfileDataGridNode: function(/*ProfileDataGridNode*/ profileDataGridNode)
+ {
+ this._save();
+
+ this.selfTime = profileDataGridNode.selfTime;
+ this.totalTime = profileDataGridNode.totalTime;
+ this.numberOfCalls = profileDataGridNode.numberOfCalls;
+ },
+
+ // When focusing, we keep just the members of the callstack.
+ _keepOnlyChild: function(/*ProfileDataGridNode*/ child)
+ {
+ this._save();
+
+ this.removeChildren();
+ this.appendChild(child);
+ },
+
+ _exclude: function(aCallUID)
+ {
+ if (this._remainingNodeInfos)
+ this._populate();
+
+ this._save();
+
+ var children = this.children;
+ var index = this.children.length;
+
+ while (index--)
+ children[index]._exclude(aCallUID);
+
+ var child = this.childrenByCallUID[aCallUID];
+
+ if (child)
+ this._merge(child, true);
+ },
+
+ _merge: function(/*ProfileDataGridNode*/ child, /*Boolean*/ shouldAbsorb)
+ {
+ this.selfTime -= child.selfTime;
+
+ WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb);
+ },
+
+ _populate: function(event)
+ {
+ var remainingNodeInfos = this._remainingNodeInfos;
+ var count = remainingNodeInfos.length;
+
+ for (var index = 0; index < count; ++index) {
+ var nodeInfo = remainingNodeInfos[index];
+ var ancestor = nodeInfo.ancestor;
+ var focusNode = nodeInfo.focusNode;
+ var child = this.findChild(ancestor);
+
+ // If we already have this child, then merge the data together.
+ if (child) {
+ var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
+
+ child.selfTime += focusNode.selfTime;
+ child.numberOfCalls += focusNode.numberOfCalls;
+
+ if (!totalTimeAccountedFor)
+ child.totalTime += focusNode.totalTime;
+ } else {
+ // If not, add it as a true ancestor.
+ // In heavy mode, we take our visual identity from ancestor node...
+ var child = new WebInspector.BottomUpProfileDataGridNode(this.profileView, ancestor, this.tree);
+
+ if (ancestor !== focusNode) {
+ // but the actual statistics from the "root" node (bottom of the callstack).
+ child.selfTime = focusNode.selfTime;
+ child.totalTime = focusNode.totalTime;
+ child.numberOfCalls = focusNode.numberOfCalls;
+ }
+
+ this.appendChild(child);
+ }
+
+ var parent = ancestor.parent;
+ if (parent && parent.parent) {
+ nodeInfo.ancestor = parent;
+ child._remainingNodeInfos.push(nodeInfo);
+ }
+ }
+
+ delete this._remainingNodeInfos;
+
+ if (this.removeEventListener)
+ this.removeEventListener("populate", this._populate, this);
+ }
+}
+
+WebInspector.BottomUpProfileDataGridNode.prototype.__proto__ = WebInspector.ProfileDataGridNode.prototype;
diff --git a/WebCore/inspector/front-end/Console.js b/WebCore/inspector/front-end/Console.js
index ba879a0..65cc7d0 100644
--- a/WebCore/inspector/front-end/Console.js
+++ b/WebCore/inspector/front-end/Console.js
@@ -577,31 +577,36 @@ WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, rep
this.url = url;
this.groupLevel = groupLevel;
this.repeatCount = repeatCount;
-
- switch (this.level) {
- case WebInspector.ConsoleMessage.MessageLevel.Trace:
- var span = document.createElement("span");
- span.addStyleClass("console-formatted-trace");
- var stack = Array.prototype.slice.call(arguments, 6);
- var funcNames = stack.map(function(f) {
- return f || WebInspector.UIString("(anonymous function)");
- });
- span.appendChild(document.createTextNode(funcNames.join("\n")));
- this.formattedMessage = span;
- break;
- case WebInspector.ConsoleMessage.MessageLevel.Object:
- this.formattedMessage = this._format(["%O", arguments[6]]);
- break;
- default:
- this.formattedMessage = this._format(Array.prototype.slice.call(arguments, 6));
- break;
- }
-
- // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
- this.message = this.formattedMessage.textContent;
+ if (arguments.length > 6)
+ this.setMessageBody(Array.prototype.slice.call(arguments, 6));
}
WebInspector.ConsoleMessage.prototype = {
+ setMessageBody: function(args)
+ {
+ switch (this.level) {
+ case WebInspector.ConsoleMessage.MessageLevel.Trace:
+ var span = document.createElement("span");
+ span.addStyleClass("console-formatted-trace");
+ var stack = Array.prototype.slice.call(args);
+ var funcNames = stack.map(function(f) {
+ return f || WebInspector.UIString("(anonymous function)");
+ });
+ span.appendChild(document.createTextNode(funcNames.join("\n")));
+ this.formattedMessage = span;
+ break;
+ case WebInspector.ConsoleMessage.MessageLevel.Object:
+ this.formattedMessage = this._format(["%O", args[0]]);
+ break;
+ default:
+ this.formattedMessage = this._format(args);
+ break;
+ }
+
+ // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
+ this.message = this.formattedMessage.textContent;
+ },
+
isErrorOrWarning: function()
{
return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
diff --git a/WebCore/inspector/front-end/DataGrid.js b/WebCore/inspector/front-end/DataGrid.js
index 6f103ed..2fcb08c 100644
--- a/WebCore/inspector/front-end/DataGrid.js
+++ b/WebCore/inspector/front-end/DataGrid.js
@@ -169,32 +169,19 @@ WebInspector.DataGrid.prototype = {
insertChild: function(child, index)
{
if (!child)
- throw("Node can't be undefined or null.");
+ throw("insertChild: Node can't be undefined or null.");
if (child.parent === this)
- throw("Node is already a child of this node.");
+ throw("insertChild: Node is already a child of this node.");
if (child.parent)
child.parent.removeChild(child);
- var previousChild = (index > 0 ? this.children[index - 1] : null);
- if (previousChild) {
- previousChild.nextSibling = child;
- child.previousSibling = previousChild;
- } else
- child.previousSibling = null;
-
- var nextChild = this.children[index];
- if (nextChild) {
- nextChild.previousSibling = child;
- child.nextSibling = nextChild;
- } else
- child.nextSibling = null;
-
this.children.splice(index, 0, child);
this.hasChildren = true;
child.parent = this;
child.dataGrid = this.dataGrid;
+ child._recalculateSiblings(index);
delete child._depth;
delete child._revealed;
@@ -216,9 +203,9 @@ WebInspector.DataGrid.prototype = {
removeChild: function(child)
{
if (!child)
- throw("Node can't be undefined or null.");
+ throw("removeChild: Node can't be undefined or null.");
if (child.parent !== this)
- throw("Node is not a child of this node.");
+ throw("removeChild: Node is not a child of this node.");
child.deselect();
@@ -233,6 +220,9 @@ WebInspector.DataGrid.prototype = {
child.parent = null;
child.nextSibling = null;
child.previousSibling = null;
+
+ if (this.children.length <= 0)
+ this.hasChildren = false;
},
removeChildren: function()
@@ -249,6 +239,7 @@ WebInspector.DataGrid.prototype = {
}
this.children = [];
+ this.hasChildren = false;
},
removeChildrenRecursive: function()
@@ -405,7 +396,7 @@ WebInspector.DataGrid.prototype = {
var gridNode = this.dataGridNodeFromEvent(event);
if (!gridNode || !gridNode.selectable)
return;
-
+
if (gridNode.isEventWithinDisclosureTriangle(event))
return;
@@ -519,6 +510,34 @@ WebInspector.DataGridNode.prototype = {
return true;
},
+ set hasChildren(x)
+ {
+ if (this._hasChildren === x)
+ return;
+
+ this._hasChildren = x;
+
+ if (!this._element)
+ return;
+
+ if (this._hasChildren)
+ {
+ this._element.addStyleClass("parent");
+ if (this.expanded)
+ this._element.addStyleClass("expanded");
+ }
+ else
+ {
+ this._element.removeStyleClass("parent");
+ this._element.removeStyleClass("expanded");
+ }
+ },
+
+ get hasChildren()
+ {
+ return this._hasChildren;
+ },
+
set revealed(x)
{
if (this._revealed === x)
@@ -624,6 +643,28 @@ WebInspector.DataGridNode.prototype = {
removeChildren: WebInspector.DataGrid.prototype.removeChildren,
removeChildrenRecursive: WebInspector.DataGrid.prototype.removeChildrenRecursive,
+ _recalculateSiblings: function(myIndex)
+ {
+ if (!this.parent)
+ return;
+
+ var previousChild = (myIndex > 0 ? this.parent.children[myIndex - 1] : null);
+
+ if (previousChild) {
+ previousChild.nextSibling = this;
+ this.previousSibling = previousChild;
+ } else
+ this.previousSibling = null;
+
+ var nextChild = this.parent.children[myIndex + 1];
+
+ if (nextChild) {
+ nextChild.previousSibling = this;
+ this.nextSibling = nextChild;
+ } else
+ this.nextSibling = null;
+ },
+
collapse: function()
{
if (this._element)
diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js
index 16e31b8..2da2f10 100644
--- a/WebCore/inspector/front-end/ElementsTreeOutline.js
+++ b/WebCore/inspector/front-end/ElementsTreeOutline.js
@@ -487,7 +487,7 @@ WebInspector.ElementsTreeElement.prototype = {
return;
if (this.treeOutline.panel) {
- this.treeOutline.rootDOMNode = this.parent.representedObject;
+ this.treeOutline.rootDOMNode = this.representedObject.parentNode;
this.treeOutline.focusedDOMNode = this.representedObject;
}
@@ -571,7 +571,7 @@ WebInspector.ElementsTreeElement.prototype = {
parseContainerElement.innerHTML = "<span " + newText + "></span>";
var parseElement = parseContainerElement.firstChild;
if (!parseElement || !parseElement.hasAttributes()) {
- editingCancelled(element, context);
+ this._editingCancelled(element, context);
return;
}
diff --git a/WebCore/inspector/front-end/Images/radioDot.png b/WebCore/inspector/front-end/Images/radioDot.png
new file mode 100644
index 0000000..609878f
--- /dev/null
+++ b/WebCore/inspector/front-end/Images/radioDot.png
Binary files differ
diff --git a/WebCore/inspector/front-end/PanelEnablerView.js b/WebCore/inspector/front-end/PanelEnablerView.js
index 6ec565b..fab6d76 100644
--- a/WebCore/inspector/front-end/PanelEnablerView.js
+++ b/WebCore/inspector/front-end/PanelEnablerView.js
@@ -44,6 +44,23 @@ WebInspector.PanelEnablerView = function(identifier, headingText, disclaimerText
this.headerElement.textContent = headingText;
this.choicesForm.appendChild(this.headerElement);
+ var self = this;
+ function enableOption(text, checked) {
+ var label = document.createElement("label");
+ var option = document.createElement("input");
+ option.type = "radio";
+ option.name = "enable-option";
+ if (checked)
+ option.checked = true;
+ label.appendChild(option);
+ label.appendChild(document.createTextNode(text));
+ self.choicesForm.appendChild(label);
+ return option;
+ };
+
+ this.enabledForSession = enableOption(WebInspector.UIString("Only enable for this session"), true);
+ this.enabledAlways = enableOption(WebInspector.UIString("Always enable"));
+
this.disclaimerElement = document.createElement("div");
this.disclaimerElement.className = "panel-enabler-disclaimer";
this.disclaimerElement.textContent = disclaimerText;
@@ -70,6 +87,10 @@ WebInspector.PanelEnablerView.prototype = {
if (this.element.offsetWidth < (this.choicesForm.offsetWidth + this.imageElement.offsetWidth))
this.imageElement.addStyleClass("hidden");
+ },
+
+ get alwaysEnabled() {
+ return this.enabledAlways.checked;
}
}
diff --git a/WebCore/inspector/front-end/ProfileDataGridTree.js b/WebCore/inspector/front-end/ProfileDataGridTree.js
new file mode 100644
index 0000000..84d9923
--- /dev/null
+++ b/WebCore/inspector/front-end/ProfileDataGridTree.js
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2009 280 North 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.ProfileDataGridNode = function(profileView, profileNode, owningTree, hasChildren)
+{
+ this.profileView = profileView;
+ this.profileNode = profileNode;
+
+ WebInspector.DataGridNode.call(this, null, hasChildren);
+
+ this.addEventListener("populate", this._populate, this);
+
+ this.tree = owningTree;
+
+ this.childrenByCallUID = {};
+ this.lastComparator = null;
+
+ this.callUID = profileNode.callUID;
+ this.selfTime = profileNode.selfTime;
+ this.totalTime = profileNode.totalTime;
+ this.functionName = profileNode.functionName;
+ this.numberOfCalls = profileNode.numberOfCalls;
+ this.url = profileNode.url;
+}
+
+WebInspector.ProfileDataGridNode.prototype = {
+ get data()
+ {
+ function formatMilliseconds(time)
+ {
+ return Number.secondsToString(time / 1000, WebInspector.UIString.bind(WebInspector), true);
+ }
+
+ var data = {};
+
+ data["function"] = this.functionName;
+ data["calls"] = this.numberOfCalls;
+
+ if (this.profileView.showSelfTimeAsPercent)
+ data["self"] = WebInspector.UIString("%.2f%%", this.selfPercent);
+ else
+ data["self"] = formatMilliseconds(this.selfTime);
+
+ if (this.profileView.showTotalTimeAsPercent)
+ data["total"] = WebInspector.UIString("%.2f%%", this.totalPercent);
+ else
+ data["total"] = formatMilliseconds(this.totalTime);
+
+ if (this.profileView.showAverageTimeAsPercent)
+ data["average"] = WebInspector.UIString("%.2f%%", this.averagePercent);
+ else
+ data["average"] = formatMilliseconds(this.averageTime);
+
+ return data;
+ },
+
+ createCell: function(columnIdentifier)
+ {
+ var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
+
+ if (columnIdentifier === "self" && this._searchMatchedSelfColumn)
+ cell.addStyleClass("highlight");
+ else if (columnIdentifier === "total" && this._searchMatchedTotalColumn)
+ cell.addStyleClass("highlight");
+ else if (columnIdentifier === "average" && this._searchMatchedAverageColumn)
+ cell.addStyleClass("highlight");
+ else if (columnIdentifier === "calls" && this._searchMatchedCallsColumn)
+ cell.addStyleClass("highlight");
+
+ if (columnIdentifier !== "function")
+ return cell;
+
+ if (this.profileNode._searchMatchedFunctionColumn)
+ cell.addStyleClass("highlight");
+
+ if (this.profileNode.url) {
+ var fileName = WebInspector.displayNameForURL(this.profileNode.url);
+
+ var urlElement = document.createElement("a");
+ urlElement.className = "profile-node-file webkit-html-resource-link";
+ urlElement.href = this.profileNode.url;
+ urlElement.lineNumber = this.profileNode.lineNumber;
+
+ if (this.profileNode.lineNumber > 0)
+ urlElement.textContent = fileName + ":" + this.profileNode.lineNumber;
+ else
+ urlElement.textContent = fileName;
+
+ cell.insertBefore(urlElement, cell.firstChild);
+ }
+
+ return cell;
+ },
+
+ select: function(supressSelectedEvent)
+ {
+ WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent);
+ this.profileView._dataGridNodeSelected(this);
+ },
+
+ deselect: function(supressDeselectedEvent)
+ {
+ WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent);
+ this.profileView._dataGridNodeDeselected(this);
+ },
+
+ expand: function()
+ {
+ if (!this.parent) {
+ var currentComparator = this.parent.lastComparator;
+
+ if (!currentComparator || (currentComparator === this.lastComparator))
+ return;
+
+ this.sort(currentComparator);
+ }
+
+ WebInspector.DataGridNode.prototype.expand.call(this);
+ },
+
+ sort: function(/*Function*/ comparator, /*Boolean*/ force)
+ {
+ var gridNodeGroups = [[this]];
+
+ for (var gridNodeGroupIndex = 0; gridNodeGroupIndex < gridNodeGroups.length; ++gridNodeGroupIndex) {
+ var gridNodes = gridNodeGroups[gridNodeGroupIndex];
+ var count = gridNodes.length;
+
+ for (var index = 0; index < count; ++index) {
+ var gridNode = gridNodes[index];
+
+ // If the grid node is collapsed, then don't sort children (save operation for later).
+ // If the grid node has the same sorting as previously, then there is no point in sorting it again.
+ if (!force && !gridNode.expanded || gridNode.lastComparator === comparator)
+ continue;
+
+ gridNode.lastComparator = comparator;
+
+ var children = gridNode.children;
+ var childCount = children.length;
+
+ if (childCount) {
+ children.sort(comparator);
+
+ for (var childIndex = 0; childIndex < childCount; ++childIndex)
+ children[childIndex]._recalculateSiblings(childIndex);
+
+ gridNodeGroups.push(children);
+ }
+ }
+ }
+ },
+
+ insertChild: function(/*ProfileDataGridNode*/ profileDataGridNode, index)
+ {
+ WebInspector.DataGridNode.prototype.insertChild.call(this, profileDataGridNode, index);
+
+ this.childrenByCallUID[profileDataGridNode.callUID] = profileDataGridNode;
+ },
+
+ removeChild: function(/*ProfileDataGridNode*/ profileDataGridNode)
+ {
+ WebInspector.DataGridNode.prototype.removeChild.call(this, profileDataGridNode);
+
+ delete this.childrenByCallUID[profileDataGridNode.callUID];
+ },
+
+ removeChildren: function(/*ProfileDataGridNode*/ profileDataGridNode)
+ {
+ WebInspector.DataGridNode.prototype.removeChildren.call(this);
+
+ this.childrenByCallUID = {};
+ },
+
+ findChild: function(/*Node*/ node)
+ {
+ if (!node)
+ return null;
+ return this.childrenByCallUID[node.callUID];
+ },
+
+ get averageTime()
+ {
+ return this.selfTime / Math.max(1, this.numberOfCalls);
+ },
+
+ get averagePercent()
+ {
+ return this.averageTime / this.tree.totalTime * 100.0;
+ },
+
+ get selfPercent()
+ {
+ return this.selfTime / this.tree.totalTime * 100.0;
+ },
+
+ get totalPercent()
+ {
+ return this.totalTime / this.tree.totalTime * 100.0;
+ },
+
+ // When focusing and collapsing we modify lots of nodes in the tree.
+ // This allows us to restore them all to their original state when we revert.
+ _save: function()
+ {
+ if (this._savedChildren)
+ return;
+
+ this._savedSelfTime = this.selfTime;
+ this._savedTotalTime = this.totalTime;
+ this._savedNumberOfCalls = this.numberOfCalls;
+
+ this._savedChildren = this.children.slice();
+ },
+
+ // When focusing and collapsing we modify lots of nodes in the tree.
+ // This allows us to restore them all to their original state when we revert.
+ _restore: function()
+ {
+ if (!this._savedChildren)
+ return;
+
+ this.selfTime = this._savedSelfTime;
+ this.totalTime = this._savedTotalTime;
+ this.numberOfCalls = this._savedNumberOfCalls;
+
+ this.removeChildren();
+
+ var children = this._savedChildren;
+ var count = children.length;
+
+ for (var index = 0; index < count; ++index) {
+ children[index]._restore();
+ this.appendChild(children[index]);
+ }
+ },
+
+ _merge: function(child, shouldAbsorb)
+ {
+ this.selfTime += child.selfTime;
+
+ if (!shouldAbsorb) {
+ this.totalTime += child.totalTime;
+ this.numberOfCalls += child.numberOfCalls;
+ }
+
+ var children = this.children.slice();
+
+ this.removeChildren();
+
+ var count = children.length;
+
+ for (var index = 0; index < count; ++index) {
+ if (!shouldAbsorb || children[index] !== child)
+ this.appendChild(children[index]);
+ }
+
+ children = child.children.slice();
+ count = children.length;
+
+ for (var index = 0; index < count; ++index) {
+ var orphanedChild = children[index],
+ existingChild = this.childrenByCallUID[orphanedChild.callUID];
+
+ if (existingChild)
+ existingChild._merge(orphanedChild, false);
+ else
+ this.appendChild(orphanedChild);
+ }
+ }
+}
+
+WebInspector.ProfileDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
+
+WebInspector.ProfileDataGridTree = function(profileView, profileNode)
+{
+ this.tree = this;
+ this.children = [];
+
+ this.profileView = profileView;
+
+ this.totalTime = profileNode.totalTime;
+ this.lastComparator = null;
+
+ this.childrenByCallUID = {};
+}
+
+WebInspector.ProfileDataGridTree.prototype = {
+ get expanded()
+ {
+ return true;
+ },
+
+ appendChild: function(child)
+ {
+ this.insertChild(child, this.children.length);
+ },
+
+ insertChild: function(child, index)
+ {
+ this.children.splice(index, 0, child);
+ this.childrenByCallUID[child.callUID] = child;
+ },
+
+ removeChildren: function()
+ {
+ this.children = [];
+ this.childrenByCallUID = {};
+ },
+
+ findChild: WebInspector.ProfileDataGridNode.prototype.findChild,
+ sort: WebInspector.ProfileDataGridNode.prototype.sort,
+
+ _save: function()
+ {
+ if (this._savedChildren)
+ return;
+
+ this._savedTotalTime = this.totalTime;
+ this._savedChildren = this.children.slice();
+ },
+
+ restore: function()
+ {
+ if (!this._savedChildren)
+ return;
+
+ this.children = this._savedChildren;
+ this.totalTime = this._savedTotalTime;
+
+ var children = this.children;
+ var count = children.length;
+
+ for (var index = 0; index < count; ++index)
+ children[index]._restore();
+
+ this._savedChildren = null;
+ }
+}
+
+WebInspector.ProfileDataGridTree.propertyComparators = [{}, {}];
+
+WebInspector.ProfileDataGridTree.propertyComparator = function(/*String*/ property, /*Boolean*/ isAscending)
+{
+ var comparator = this.propertyComparators[(isAscending ? 1 : 0)][property];
+
+ if (!comparator) {
+ if (isAscending) {
+ comparator = function(lhs, rhs)
+ {
+ if (lhs[property] < rhs[property])
+ return -1;
+
+ if (lhs[property] > rhs[property])
+ return 1;
+
+ return 0;
+ }
+ } else {
+ comparator = function(lhs, rhs)
+ {
+ if (lhs[property] > rhs[property])
+ return -1;
+
+ if (lhs[property] < rhs[property])
+ return 1;
+
+ return 0;
+ }
+ }
+
+ this.propertyComparators[(isAscending ? 1 : 0)][property] = comparator;
+ }
+
+ return comparator;
+}
diff --git a/WebCore/inspector/front-end/ProfileView.js b/WebCore/inspector/front-end/ProfileView.js
index 92e9726..d00733c 100644
--- a/WebCore/inspector/front-end/ProfileView.js
+++ b/WebCore/inspector/front-end/ProfileView.js
@@ -31,9 +31,11 @@ WebInspector.ProfileView = function(profile)
this.showSelfTimeAsPercent = true;
this.showTotalTimeAsPercent = true;
+ this.showAverageTimeAsPercent = true;
var columns = { "self": { title: WebInspector.UIString("Self"), width: "72px", sort: "descending", sortable: true },
"total": { title: WebInspector.UIString("Total"), width: "72px", sortable: true },
+ "average": { title: WebInspector.UIString("Average"), width: "72px", sortable: true },
"calls": { title: WebInspector.UIString("Calls"), width: "54px", sortable: true },
"function": { title: WebInspector.UIString("Function"), disclosure: true, sortable: true } };
@@ -75,16 +77,14 @@ WebInspector.ProfileView = function(profile)
this.resetButton.className = "reset-profile-status-bar-item status-bar-item hidden";
this.resetButton.addEventListener("click", this._resetClicked.bind(this), false);
- // Default to the heavy profile.
- profile = profile.heavyProfile;
+ this.profile = profile;
- // By default the profile isn't sorted, so sort based on our default sort
- // column and direction added to the DataGrid columns above.
- profile.sortSelfTimeDescending();
+ this.profileDataGridTree = this.bottomUpProfileDataGridTree;
+ this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator("selfTime", false));
- this._updatePercentButton();
+ this.refresh();
- this.profile = profile;
+ this._updatePercentButton();
}
WebInspector.ProfileView.prototype = {
@@ -101,9 +101,53 @@ WebInspector.ProfileView.prototype = {
set profile(profile)
{
this._profile = profile;
+ },
+
+ get bottomUpProfileDataGridTree()
+ {
+ if (!this._bottomUpProfileDataGridTree)
+ this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, this.profile.head);
+ return this._bottomUpProfileDataGridTree;
+ },
+
+ get topDownProfileDataGridTree()
+ {
+ if (!this._topDownProfileDataGridTree)
+ this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profile.head);
+ return this._topDownProfileDataGridTree;
+ },
+
+ get currentTree()
+ {
+ return this._currentTree;
+ },
+
+ set currentTree(tree)
+ {
+ this._currentTree = tree;
this.refresh();
},
+ get topDownTree()
+ {
+ if (!this._topDownTree) {
+ this._topDownTree = WebInspector.TopDownTreeFactory.create(this.profile.head);
+ this._sortProfile(this._topDownTree);
+ }
+
+ return this._topDownTree;
+ },
+
+ get bottomUpTree()
+ {
+ if (!this._bottomUpTree) {
+ this._bottomUpTree = WebInspector.BottomUpTreeFactory.create(this.profile.head);
+ this._sortProfile(this._bottomUpTree);
+ }
+
+ return this._bottomUpTree;
+ },
+
hide: function()
{
WebInspector.View.prototype.hide.call(this);
@@ -116,20 +160,18 @@ WebInspector.ProfileView.prototype = {
this.dataGrid.removeChildren();
- var children = this.profile.head.children;
- var childrenLength = children.length;
- for (var i = 0; i < childrenLength; ++i)
- if (children[i].visible)
- this.dataGrid.appendChild(new WebInspector.ProfileDataGridNode(this, children[i]));
+ var children = this.profileDataGridTree.children;
+ var count = children.length;
+
+ for (var index = 0; index < count; ++index)
+ this.dataGrid.appendChild(children[index]);
if (selectedProfileNode && selectedProfileNode._dataGridNode)
selectedProfileNode._dataGridNode.selected = true;
},
- refreshShowAsPercents: function()
+ refreshVisibleData: function()
{
- this._updatePercentButton();
-
var child = this.dataGrid.children[0];
while (child) {
child.refresh();
@@ -137,6 +179,12 @@ WebInspector.ProfileView.prototype = {
}
},
+ refreshShowAsPercents: function()
+ {
+ this._updatePercentButton();
+ this.refreshVisibleData();
+ },
+
searchCanceled: function()
{
if (this._searchResults) {
@@ -191,71 +239,90 @@ WebInspector.ProfileView.prototype = {
if (!isNaN(queryNumber) && !(greaterThan || lessThan))
equalTo = true;
- function matchesQuery(profileNode)
+ function matchesQuery(/*ProfileDataGridNode*/ profileDataGridNode)
{
- delete profileNode._searchMatchedSelfColumn;
- delete profileNode._searchMatchedTotalColumn;
- delete profileNode._searchMatchedCallsColumn;
- delete profileNode._searchMatchedFunctionColumn;
+ delete profileDataGridNode._searchMatchedSelfColumn;
+ delete profileDataGridNode._searchMatchedTotalColumn;
+ delete profileDataGridNode._searchMatchedAverageColumn;
+ delete profileDataGridNode._searchMatchedCallsColumn;
+ delete profileDataGridNode._searchMatchedFunctionColumn;
if (percentUnits) {
if (lessThan) {
- if (profileNode.selfPercent < queryNumber)
- profileNode._searchMatchedSelfColumn = true;
- if (profileNode.totalPercent < queryNumber)
- profileNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.selfPercent < queryNumber)
+ profileDataGridNode._searchMatchedSelfColumn = true;
+ if (profileDataGridNode.totalPercent < queryNumber)
+ profileDataGridNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedAverageColumn = true;
} else if (greaterThan) {
- if (profileNode.selfPercent > queryNumber)
- profileNode._searchMatchedSelfColumn = true;
- if (profileNode.totalPercent > queryNumber)
- profileNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.selfPercent > queryNumber)
+ profileDataGridNode._searchMatchedSelfColumn = true;
+ if (profileDataGridNode.totalPercent > queryNumber)
+ profileDataGridNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedAverageColumn = true;
}
if (equalTo) {
- if (profileNode.selfPercent == queryNumber)
- profileNode._searchMatchedSelfColumn = true;
- if (profileNode.totalPercent == queryNumber)
- profileNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.selfPercent == queryNumber)
+ profileDataGridNode._searchMatchedSelfColumn = true;
+ if (profileDataGridNode.totalPercent == queryNumber)
+ profileDataGridNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.averagePercent < queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedAverageColumn = true;
}
} else if (millisecondsUnits || secondsUnits) {
if (lessThan) {
- if (profileNode.selfTime < queryNumberMilliseconds)
- profileNode._searchMatchedSelfColumn = true;
- if (profileNode.totalTime < queryNumberMilliseconds)
- profileNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.selfTime < queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedSelfColumn = true;
+ if (profileDataGridNode.totalTime < queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.averageTime < queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedAverageColumn = true;
} else if (greaterThan) {
- if (profileNode.selfTime > queryNumberMilliseconds)
- profileNode._searchMatchedSelfColumn = true;
- if (profileNode.totalTime > queryNumberMilliseconds)
- profileNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.selfTime > queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedSelfColumn = true;
+ if (profileDataGridNode.totalTime > queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.averageTime > queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedAverageColumn = true;
}
if (equalTo) {
- if (profileNode.selfTime == queryNumberMilliseconds)
- profileNode._searchMatchedSelfColumn = true;
- if (profileNode.totalTime == queryNumberMilliseconds)
- profileNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.selfTime == queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedSelfColumn = true;
+ if (profileDataGridNode.totalTime == queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedTotalColumn = true;
+ if (profileDataGridNode.averageTime == queryNumberMilliseconds)
+ profileDataGridNode._searchMatchedAverageColumn = true;
}
} else {
- if (equalTo && profileNode.numberOfCalls == queryNumber)
- profileNode._searchMatchedCallsColumn = true;
- if (greaterThan && profileNode.numberOfCalls > queryNumber)
- profileNode._searchMatchedCallsColumn = true;
- if (lessThan && profileNode.numberOfCalls < queryNumber)
- profileNode._searchMatchedCallsColumn = true;
+ if (equalTo && profileDataGridNode.numberOfCalls == queryNumber)
+ profileDataGridNode._searchMatchedCallsColumn = true;
+ if (greaterThan && profileDataGridNode.numberOfCalls > queryNumber)
+ profileDataGridNode._searchMatchedCallsColumn = true;
+ if (lessThan && profileDataGridNode.numberOfCalls < queryNumber)
+ profileDataGridNode._searchMatchedCallsColumn = true;
}
- if (profileNode.functionName.hasSubstring(query, true) || profileNode.url.hasSubstring(query, true))
- profileNode._searchMatchedFunctionColumn = true;
-
- var matched = (profileNode._searchMatchedSelfColumn || profileNode._searchMatchedTotalColumn || profileNode._searchMatchedCallsColumn || profileNode._searchMatchedFunctionColumn);
- if (matched && profileNode._dataGridNode)
- profileNode._dataGridNode.refresh();
+ if (profileDataGridNode.functionName.hasSubstring(query, true) || profileDataGridNode.url.hasSubstring(query, true))
+ profileDataGridNode._searchMatchedFunctionColumn = true;
+
+ if (profileDataGridNode._searchMatchedSelfColumn ||
+ profileDataGridNode._searchMatchedTotalColumn ||
+ profileDataGridNode._searchMatchedAverageColumn ||
+ profileDataGridNode._searchMatchedCallsColumn ||
+ profileDataGridNode._searchMatchedFunctionColumn);
+ {
+ profileDataGridNode.refresh();
+ return true;
+ }
- return matched;
+ return false;
}
- var current = this.profile.head;
+ var current = this.dataGrid;
var ancestors = [];
var nextIndexes = [];
var startIndex = 0;
@@ -380,12 +447,12 @@ WebInspector.ProfileView.prototype = {
return;
if (event.target.selectedIndex == 1 && this.view == "Heavy") {
- this._sortProfile(this.profile.treeProfile);
- this.profile = this.profile.treeProfile;
+ this.profileDataGridTree = this.topDownProfileDataGridTree;
+ this._sortProfile();
this.view = "Tree";
} else if (event.target.selectedIndex == 0 && this.view == "Tree") {
- this._sortProfile(this.profile.heavyProfile);
- this.profile = this.profile.heavyProfile;
+ this.profileDataGridTree = this.bottomUpProfileDataGridTree;
+ this._sortProfile();
this.view = "Heavy";
}
@@ -401,15 +468,16 @@ WebInspector.ProfileView.prototype = {
_percentClicked: function(event)
{
- var currentState = this.showSelfTimeAsPercent && this.showTotalTimeAsPercent;
+ var currentState = this.showSelfTimeAsPercent && this.showTotalTimeAsPercent && this.showAverageTimeAsPercent;
this.showSelfTimeAsPercent = !currentState;
this.showTotalTimeAsPercent = !currentState;
+ this.showAverageTimeAsPercent = !currentState;
this.refreshShowAsPercents();
},
_updatePercentButton: function()
{
- if (this.showSelfTimeAsPercent && this.showTotalTimeAsPercent) {
+ if (this.showSelfTimeAsPercent && this.showTotalTimeAsPercent && this.showAverageTimeAsPercent) {
this.percentButton.title = WebInspector.UIString("Show absolute total and self times.");
this.percentButton.addStyleClass("toggled-on");
} else {
@@ -420,28 +488,36 @@ WebInspector.ProfileView.prototype = {
_focusClicked: function(event)
{
- if (!this.dataGrid.selectedNode || !this.dataGrid.selectedNode.profileNode)
+ if (!this.dataGrid.selectedNode)
return;
+
this.resetButton.removeStyleClass("hidden");
- this.profile.focus(this.dataGrid.selectedNode.profileNode);
+ this.profileDataGridTree.focus(this.dataGrid.selectedNode);
this.refresh();
+ this.refreshVisibleData();
},
_excludeClicked: function(event)
{
- if (!this.dataGrid.selectedNode || !this.dataGrid.selectedNode.profileNode)
+ var selectedNode = this.dataGrid.selectedNode
+
+ if (!selectedNode)
return;
+
+ selectedNode.deselect();
+
this.resetButton.removeStyleClass("hidden");
- this.profile.exclude(this.dataGrid.selectedNode.profileNode);
- this.dataGrid.selectedNode.deselect();
+ this.profileDataGridTree.exclude(selectedNode);
this.refresh();
+ this.refreshVisibleData();
},
_resetClicked: function(event)
{
this.resetButton.addStyleClass("hidden");
- this.profile.restoreAll();
+ this.profileDataGridTree.restore();
this.refresh();
+ this.refreshVisibleData();
},
_dataGridNodeSelected: function(node)
@@ -461,37 +537,21 @@ WebInspector.ProfileView.prototype = {
this._sortProfile(this.profile);
},
- _sortProfile: function(profile)
+ _sortProfile: function()
{
- if (!profile)
- return;
-
- var sortOrder = this.dataGrid.sortOrder;
+ var sortAscending = this.dataGrid.sortOrder === "ascending";
var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
+ var sortProperty = {
+ "average": "averageTime",
+ "self": "selfTime",
+ "total": "totalTime",
+ "calls": "numberOfCalls",
+ "function": "functionName"
+ }[sortColumnIdentifier];
- var sortingFunctionName = "sort";
-
- if (sortColumnIdentifier === "self")
- sortingFunctionName += "SelfTime";
- else if (sortColumnIdentifier === "total")
- sortingFunctionName += "TotalTime";
- else if (sortColumnIdentifier === "calls")
- sortingFunctionName += "Calls";
- else if (sortColumnIdentifier === "function")
- sortingFunctionName += "FunctionName";
-
- if (sortOrder === "ascending")
- sortingFunctionName += "Ascending";
- else
- sortingFunctionName += "Descending";
-
- if (!(sortingFunctionName in this.profile))
- return;
-
- profile[sortingFunctionName]();
+ this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending));
- if (profile === this.profile)
- this.refresh();
+ this.refresh();
},
_mouseDownInDataGrid: function(event)
@@ -500,13 +560,15 @@ WebInspector.ProfileView.prototype = {
return;
var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
- if (!cell || (!cell.hasStyleClass("total-column") && !cell.hasStyleClass("self-column")))
+ if (!cell || (!cell.hasStyleClass("total-column") && !cell.hasStyleClass("self-column") && !cell.hasStyleClass("average-column")))
return;
if (cell.hasStyleClass("total-column"))
this.showTotalTimeAsPercent = !this.showTotalTimeAsPercent;
else if (cell.hasStyleClass("self-column"))
this.showSelfTimeAsPercent = !this.showSelfTimeAsPercent;
+ else if (cell.hasStyleClass("average-column"))
+ this.showAverageTimeAsPercent = !this.showAverageTimeAsPercent;
this.refreshShowAsPercents();
@@ -516,127 +578,3 @@ WebInspector.ProfileView.prototype = {
}
WebInspector.ProfileView.prototype.__proto__ = WebInspector.View.prototype;
-
-WebInspector.ProfileDataGridNode = function(profileView, profileNode)
-{
- this.profileView = profileView;
-
- this.profileNode = profileNode;
- profileNode._dataGridNode = this;
-
- // Find the first child that is visible. Since we don't want to claim
- // we have children if all the children are invisible.
- var hasChildren = false;
- var children = this.profileNode.children;
- var childrenLength = children.length;
- for (var i = 0; i < childrenLength; ++i) {
- if (children[i].visible) {
- hasChildren = true;
- break;
- }
- }
-
- WebInspector.DataGridNode.call(this, null, hasChildren);
-
- this.addEventListener("populate", this._populate, this);
-
- this.expanded = profileNode._expanded;
-}
-
-WebInspector.ProfileDataGridNode.prototype = {
- get data()
- {
- function formatMilliseconds(time)
- {
- return Number.secondsToString(time / 1000, WebInspector.UIString.bind(WebInspector), true);
- }
-
- var data = {};
- data["function"] = this.profileNode.functionName;
- data["calls"] = this.profileNode.numberOfCalls;
-
- if (this.profileView.showSelfTimeAsPercent)
- data["self"] = WebInspector.UIString("%.2f%%", this.profileNode.selfPercent);
- else
- data["self"] = formatMilliseconds(this.profileNode.selfTime);
-
- if (this.profileView.showTotalTimeAsPercent)
- data["total"] = WebInspector.UIString("%.2f%%", this.profileNode.totalPercent);
- else
- data["total"] = formatMilliseconds(this.profileNode.totalTime);
-
- return data;
- },
-
- createCell: function(columnIdentifier)
- {
- var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
-
- if (columnIdentifier === "self" && this.profileNode._searchMatchedSelfColumn)
- cell.addStyleClass("highlight");
- else if (columnIdentifier === "total" && this.profileNode._searchMatchedTotalColumn)
- cell.addStyleClass("highlight");
- else if (columnIdentifier === "calls" && this.profileNode._searchMatchedCallsColumn)
- cell.addStyleClass("highlight");
-
- if (columnIdentifier !== "function")
- return cell;
-
- if (this.profileNode._searchMatchedFunctionColumn)
- cell.addStyleClass("highlight");
-
- if (this.profileNode.url) {
- var fileName = WebInspector.displayNameForURL(this.profileNode.url);
-
- var urlElement = document.createElement("a");
- urlElement.className = "profile-node-file webkit-html-resource-link";
- urlElement.href = this.profileNode.url;
- urlElement.lineNumber = this.profileNode.lineNumber;
-
- if (this.profileNode.lineNumber > 0)
- urlElement.textContent = fileName + ":" + this.profileNode.lineNumber;
- else
- urlElement.textContent = fileName;
-
- cell.insertBefore(urlElement, cell.firstChild);
- }
-
- return cell;
- },
-
- select: function(supressSelectedEvent)
- {
- WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent);
- this.profileView._dataGridNodeSelected(this);
- },
-
- deselect: function(supressDeselectedEvent)
- {
- WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent);
- this.profileView._dataGridNodeDeselected(this);
- },
-
- expand: function()
- {
- WebInspector.DataGridNode.prototype.expand.call(this);
- this.profileNode._expanded = true;
- },
-
- collapse: function()
- {
- WebInspector.DataGridNode.prototype.collapse.call(this);
- this.profileNode._expanded = false;
- },
-
- _populate: function(event)
- {
- var children = this.profileNode.children;
- var childrenLength = children.length;
- for (var i = 0; i < childrenLength; ++i)
- if (children[i].visible)
- this.appendChild(new WebInspector.ProfileDataGridNode(this.profileView, children[i]));
- this.removeEventListener("populate", this._populate, this);
- }
-}
-
-WebInspector.ProfileDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js
index ea3b85c..aafc306 100644
--- a/WebCore/inspector/front-end/ProfilesPanel.js
+++ b/WebCore/inspector/front-end/ProfilesPanel.js
@@ -218,7 +218,7 @@ WebInspector.ProfilesPanel.prototype = {
view.show(this.profileViews);
profile._profilesTreeElement.select(true);
- profile._profilesTreeElement.reveal()
+ profile._profilesTreeElement.reveal();
this.visibleView = view;
@@ -231,8 +231,7 @@ WebInspector.ProfilesPanel.prototype = {
showView: function(view)
{
- // Always use the treeProfile, since the heavy profile might be showing.
- this.showProfile(view.profile.treeProfile);
+ this.showProfile(view.profile);
},
profileViewForProfile: function(profile)
@@ -295,8 +294,7 @@ WebInspector.ProfilesPanel.prototype = {
searchMatchFound: function(view, matches)
{
- // Always use the treeProfile, since the heavy profile might be showing.
- view.profile.treeProfile._profilesTreeElement.searchMatches = matches;
+ view.profile._profilesTreeElement.searchMatches = matches;
},
searchCanceled: function(startingNewSearch)
@@ -356,15 +354,15 @@ WebInspector.ProfilesPanel.prototype = {
{
if (InspectorController.profilerEnabled())
return;
- this._toggleProfiling();
+ this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
},
- _toggleProfiling: function()
+ _toggleProfiling: function(optionalAlways)
{
if (InspectorController.profilerEnabled())
- InspectorController.disableProfiler();
+ InspectorController.disableProfiler(true);
else
- InspectorController.enableProfiler();
+ InspectorController.enableProfiler(!!optionalAlways);
},
_populateProfiles: function()
diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js
index e02baf3..04d998e 100644
--- a/WebCore/inspector/front-end/ResourcesPanel.js
+++ b/WebCore/inspector/front-end/ResourcesPanel.js
@@ -126,6 +126,19 @@ WebInspector.ResourcesPanel = function()
this.resourcesTreeElement.expand();
+ var panelEnablerHeading = WebInspector.UIString("You need to enable resource tracking to use the this panel.");
+ var panelEnablerDisclaimer = WebInspector.UIString("Enabling resource tracking will reload the page and make page loading slower.");
+ var panelEnablerButton = WebInspector.UIString("Enable resource tracking");
+
+ this.panelEnablerView = new WebInspector.PanelEnablerView("resources", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
+ this.panelEnablerView.addEventListener("enable clicked", this._enableResourceTracking, this);
+
+ this.element.appendChild(this.panelEnablerView.element);
+
+ this.enableToggleButton = document.createElement("button");
+ this.enableToggleButton.className = "enable-toggle-status-bar-item status-bar-item";
+ this.enableToggleButton.addEventListener("click", this._toggleResourceTracking.bind(this), false);
+
this.largerResourcesButton = document.createElement("button");
this.largerResourcesButton.id = "resources-larger-resources-status-bar-item";
this.largerResourcesButton.className = "status-bar-item toggled-on";
@@ -151,7 +164,7 @@ WebInspector.ResourcesPanel.prototype = {
get statusBarItems()
{
- return [this.largerResourcesButton, this.sortingSelectElement];
+ return [this.enableToggleButton, this.largerResourcesButton, this.sortingSelectElement];
},
show: function()
@@ -358,6 +371,16 @@ WebInspector.ResourcesPanel.prototype = {
this._updateSummaryGraph();
},
+ resourceTrackingWasEnabled: function()
+ {
+ this.reset();
+ },
+
+ resourceTrackingWasDisabled: function()
+ {
+ this.reset();
+ },
+
reset: function()
{
this.closeVisibleResource();
@@ -394,6 +417,20 @@ WebInspector.ResourcesPanel.prototype = {
this._updateGraphDividersIfNeeded(true);
this._drawSummaryGraph(); // draws an empty graph
+
+ if (InspectorController.resourceTrackingEnabled()) {
+ this.enableToggleButton.title = WebInspector.UIString("Resource tracking enabled. Click to disable.");
+ this.enableToggleButton.addStyleClass("toggled-on");
+ this.largerResourcesButton.removeStyleClass("hidden");
+ this.sortingSelectElement.removeStyleClass("hidden");
+ this.panelEnablerView.visible = false;
+ } else {
+ this.enableToggleButton.title = WebInspector.UIString("Resource tracking disabled. Click to enable.");
+ this.enableToggleButton.removeStyleClass("toggled-on");
+ this.largerResourcesButton.addStyleClass("hidden");
+ this.sortingSelectElement.addStyleClass("hidden");
+ this.panelEnablerView.visible = true;
+ }
},
addResource: function(resource)
@@ -1085,6 +1122,26 @@ WebInspector.ResourcesPanel.prototype = {
var visibleView = this.visibleView;
if (visibleView && "resize" in visibleView)
visibleView.resize();
+ },
+
+ _enableResourceTracking: function()
+ {
+ if (InspectorController.resourceTrackingEnabled())
+ return;
+ this._toggleResourceTracking(this.panelEnablerView.alwaysEnabled);
+ },
+
+ _toggleResourceTracking: function(optionalAlways)
+ {
+ if (InspectorController.resourceTrackingEnabled()) {
+ this.largerResourcesButton.visible = false;
+ this.sortingSelectElement.visible = false;
+ InspectorController.disableResourceTracking(true);
+ } else {
+ this.largerResourcesButton.visible = true;
+ this.sortingSelectElement.visible = true;
+ InspectorController.enableResourceTracking(!!optionalAlways);
+ }
}
}
diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js
index 2792834..7af9292 100644
--- a/WebCore/inspector/front-end/ScriptsPanel.js
+++ b/WebCore/inspector/front-end/ScriptsPanel.js
@@ -205,6 +205,10 @@ WebInspector.ScriptsPanel.prototype = {
continue;
view.visible = false;
}
+ if (this._attachDebuggerWhenShown) {
+ InspectorController.enableDebuggerFromFrontend(false);
+ delete this._attachDebuggerWhenShown;
+ }
},
get searchableViews()
@@ -359,6 +363,24 @@ WebInspector.ScriptsPanel.prototype = {
window.focus();
},
+ debuggerResumed: function()
+ {
+ this._paused = false;
+ this._waitingToPause = false;
+ this._stepping = false;
+
+ this._clearInterface();
+ },
+
+ attachDebuggerWhenShown: function()
+ {
+ if (this.element.parentElement) {
+ InspectorController.enableDebuggerFromFrontend(false);
+ } else {
+ this._attachDebuggerWhenShown = true;
+ }
+ },
+
debuggerWasEnabled: function()
{
this.reset();
@@ -573,21 +595,25 @@ WebInspector.ScriptsPanel.prototype = {
option.representedObject = (script.resource || script);
option.text = (script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)"));
- var insertionIndex = -1;
- if (select.childNodes) {
- insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, function(a, b) {
- a = a.text.toLowerCase();
- b = b.text.toLowerCase();
-
- if (a < b)
- return -1;
- else if (a > b)
- return 1;
-
- return 0;
- });
+ function optionCompare(a, b)
+ {
+ var aTitle = a.text.toLowerCase();
+ var bTitle = b.text.toLowerCase();
+ if (aTitle < bTitle)
+ return -1;
+ else if (aTitle > bTitle)
+ return 1;
+
+ var aSourceID = a.representedObject.sourceID;
+ var bSourceID = b.representedObject.sourceID;
+ if (aSourceID < bSourceID)
+ return -1;
+ else if (aSourceID > bSourceID)
+ return 1;
+ return 0;
}
+ var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare);
if (insertionIndex < 0)
select.appendChild(option);
else
@@ -758,19 +784,19 @@ WebInspector.ScriptsPanel.prototype = {
{
if (InspectorController.debuggerEnabled())
return;
- this._toggleDebugging();
+ this._toggleDebugging(this.panelEnablerView.alwaysEnabled);
},
- _toggleDebugging: function()
+ _toggleDebugging: function(optionalAlways)
{
this._paused = false;
this._waitingToPause = false;
this._stepping = false;
if (InspectorController.debuggerEnabled())
- InspectorController.disableDebugger();
+ InspectorController.disableDebugger(true);
else
- InspectorController.enableDebugger();
+ InspectorController.enableDebuggerFromFrontend(!!optionalAlways);
},
_togglePauseOnExceptions: function()
diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js
index 26c0626..18d9073 100644
--- a/WebCore/inspector/front-end/SourceFrame.js
+++ b/WebCore/inspector/front-end/SourceFrame.js
@@ -110,6 +110,11 @@ WebInspector.SourceFrame.prototype = {
revealLine: function(lineNumber)
{
+ if (!this._isContentLoaded()) {
+ this._lineNumberToReveal = lineNumber;
+ return;
+ }
+
var row = this.sourceRow(lineNumber);
if (row)
row.scrollIntoViewIfNeeded(true);
@@ -172,6 +177,11 @@ WebInspector.SourceFrame.prototype = {
highlightLine: function(lineNumber)
{
+ if (!this._isContentLoaded()) {
+ this._lineNumberToHighlight = lineNumber;
+ return;
+ }
+
var sourceRow = this.sourceRow(lineNumber);
if (!sourceRow)
return;
@@ -233,9 +243,28 @@ WebInspector.SourceFrame.prototype = {
this._addExistingMessagesToSource();
this._addExistingBreakpointsToSource();
this._updateExecutionLine();
+ if (this._executionLine)
+ this.revealLine(this._executionLine);
if (this.autoSizesToFitContentHeight)
this.sizeToFitContentHeight();
+
+ if (this._lineNumberToReveal) {
+ this.revealLine(this._lineNumberToReveal);
+ delete this._lineNumberToReveal;
+ }
+
+ if (this._lineNumberToHighlight) {
+ this.highlightLine(this._lineNumberToHighlight);
+ delete this._lineNumberToHighlight;
+ }
+
+ this.dispatchEventToListeners("content loaded");
+ },
+
+ _isContentLoaded: function() {
+ var doc = this.element.contentDocument;
+ return doc && doc.getElementsByTagName("table")[0];
},
_windowResized: function(event)
diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js
index 309027e..7510c8c 100644
--- a/WebCore/inspector/front-end/SourceView.js
+++ b/WebCore/inspector/front-end/SourceView.js
@@ -95,10 +95,15 @@ WebInspector.SourceView.prototype = {
this.attach();
- if (!InspectorController.addResourceSourceToFrame(this.resource.identifier, this.sourceFrame.element))
- return;
-
delete this._frameNeedsSetup;
+ this.sourceFrame.addEventListener("content loaded", this._contentLoaded, this);
+ InspectorController.addResourceSourceToFrame(this.resource.identifier, this.sourceFrame.element);
+ },
+
+ _contentLoaded: function()
+ {
+ delete this._frameNeedsSetup;
+ this.sourceFrame.removeEventListener("content loaded", this._contentLoaded, this);
if (this.resource.type === WebInspector.Resource.Type.Script) {
this.sourceFrame.addEventListener("syntax highlighting complete", this._syntaxHighlightingComplete, this);
@@ -274,7 +279,7 @@ WebInspector.SourceView.prototype = {
if (!foundRange)
return;
- var selection = window.getSelection();
+ var selection = this.sourceFrame.element.contentWindow.getSelection();
selection.removeAllRanges();
selection.addRange(foundRange);
diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js
index f0a9afb..c30444b 100644
--- a/WebCore/inspector/front-end/StylesSidebarPane.js
+++ b/WebCore/inspector/front-end/StylesSidebarPane.js
@@ -586,8 +586,8 @@ WebInspector.StylePropertyTreeElement.prototype = {
this.listItemElement.appendChild(document.createTextNode(";"));
if (value) {
- // FIXME: this dosen't catch keyword based colors like black and white
- var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})/g);
+ // FIXME: this only covers W3C and CSS 16 valid color names
+ var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow/g);
if (colors) {
var colorsLength = colors.length;
for (var i = 0; i < colorsLength; ++i) {
diff --git a/WebCore/inspector/front-end/TopDownProfileDataGridTree.js b/WebCore/inspector/front-end/TopDownProfileDataGridTree.js
new file mode 100644
index 0000000..b9d8b94
--- /dev/null
+++ b/WebCore/inspector/front-end/TopDownProfileDataGridTree.js
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 280 North 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.TopDownProfileDataGridNode = function(/*ProfileView*/ profileView, /*ProfileNode*/ profileNode, /*TopDownProfileDataGridTree*/ owningTree)
+{
+ var hasChildren = (profileNode.children && profileNode.children.length);
+
+ WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, hasChildren);
+
+ this._remainingChildren = profileNode.children;
+}
+
+WebInspector.TopDownProfileDataGridNode.prototype = {
+ _populate: function(event)
+ {
+ var children = this._remainingChildren;
+ var childrenLength = children.length;
+
+ for (var i = 0; i < childrenLength; ++i)
+ this.appendChild(new WebInspector.TopDownProfileDataGridNode(this.profileView, children[i], this.tree));
+
+ if (this.removeEventListener)
+ this.removeEventListener("populate", this._populate, this);
+
+ this._remainingChildren = null;
+ },
+
+ _exclude: function(aCallUID)
+ {
+ if (this._remainingChildren)
+ this._populate();
+
+ this._save();
+
+ var children = this.children;
+ var index = this.children.length;
+
+ while (index--)
+ children[index]._exclude(aCallUID);
+
+ var child = this.childrenByCallUID[aCallUID];
+
+ if (child)
+ this._merge(child, true);
+ }
+}
+
+WebInspector.TopDownProfileDataGridNode.prototype.__proto__ = WebInspector.ProfileDataGridNode.prototype;
+
+WebInspector.TopDownProfileDataGridTree = function(/*ProfileView*/ profileView, /*ProfileNode*/ profileNode)
+{
+ WebInspector.ProfileDataGridTree.call(this, profileView, profileNode);
+
+ this._remainingChildren = profileNode.children;
+
+ WebInspector.TopDownProfileDataGridNode.prototype._populate.call(this);
+}
+
+WebInspector.TopDownProfileDataGridTree.prototype = {
+ focus: function(/*ProfileDataGridNode*/ profileDataGrideNode)
+ {
+ if (!profileDataGrideNode)
+ return;
+
+ this._save();
+
+ this.children = [profileDataGrideNode];
+ this.totalTime = profileDataGrideNode.totalTime;
+ },
+
+ exclude: function(/*ProfileDataGridNode*/ profileDataGrideNode)
+ {
+ if (!profileDataGrideNode)
+ return;
+
+ this._save();
+
+ var excludedCallUID = profileDataGrideNode.callUID;
+
+ WebInspector.TopDownProfileDataGridNode.prototype._exclude.call(this, excludedCallUID);
+
+ if (this.lastComparator)
+ this.sort(this.lastComparator, true);
+ },
+
+ _merge: WebInspector.TopDownProfileDataGridNode.prototype._merge
+}
+
+WebInspector.TopDownProfileDataGridTree.prototype.__proto__ = WebInspector.ProfileDataGridTree.prototype;
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index 997d4a7..76a925b 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -1,6 +1,7 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/webkit/inspector">
<file>inspector.html</file>
+ <file>BottomUpProfileDataGridTree.js</file>
<file>Breakpoint.js</file>
<file>BreakpointsSidebarPane.js</file>
<file>CallStackSidebarPane.js</file>
@@ -24,6 +25,7 @@
<file>Panel.js</file>
<file>PanelEnablerView.js</file>
<file>Placard.js</file>
+ <file>ProfileDataGridTree.js</file>
<file>ProfilesPanel.js</file>
<file>ProfileView.js</file>
<file>PropertiesSection.js</file>
@@ -42,6 +44,7 @@
<file>SourceView.js</file>
<file>StylesSidebarPane.js</file>
<file>TextPrompt.js</file>
+ <file>TopDownProfileDataGridTree.js</file>
<file>treeoutline.js</file>
<file>utilities.js</file>
<file>View.js</file>
@@ -96,6 +99,7 @@
<file>Images/profilesIcon.png</file>
<file>Images/profileSmallIcon.png</file>
<file>Images/profilesSilhouette.png</file>
+ <file>Images/radioDot.png</file>
<file>Images/recordButtons.png</file>
<file>Images/reloadButtons.png</file>
<file>Images/resourceCSSIcon.png</file>
@@ -155,6 +159,7 @@
<file>Images/treeUpTriangleWhite.png</file>
<file>Images/userInputIcon.png</file>
<file>Images/userInputPreviousIcon.png</file>
+ <file>Images/userInputResultIcon.png</file>
<file>Images/warningIcon.png</file>
<file>Images/warningMediumIcon.png</file>
<file>Images/warningsErrors.png</file>
diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css
index 082955e..2653781 100644
--- a/WebCore/inspector/front-end/inspector.css
+++ b/WebCore/inspector/front-end/inspector.css
@@ -1919,6 +1919,7 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
font-size: 10px;
color: rgb(110, 116, 128);
margin-bottom: 12px;
+ margin-left: 20px;
}
.panel-enabler-disclaimer:empty {
@@ -1954,10 +1955,8 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des
position: relative;
display: block;
text-align: left;
- margin-left: 50px;
- margin-bottom: 6px;
- line-height: 18px;
word-break: break-word;
+ margin: 0 0 5px 20px;
}
.panel-enabler-view button {
@@ -1986,6 +1985,30 @@ body.inactive .panel-enabler-view button, .panel-enabler-view button:disabled {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(250, 250, 250)), to(rgb(235, 235, 235)));
}
+.panel-enabler-view input {
+ height: 17px;
+ width: 17px;
+ border: 1px solid rgb(165, 165, 165);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)));
+ -webkit-border-radius: 8px;
+ -webkit-appearance: none;
+ vertical-align: middle;
+ margin: 0 5px 5px 0;
+}
+
+.panel-enabler-view input:active {
+ background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(194, 194, 194)), to(rgb(239, 239, 239)));
+}
+
+.panel-enabler-view input:checked {
+ background: url(Images/radioDot.png) center no-repeat,
+ -webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)));
+}
+
+.panel-enabler-view.resources img {
+ content: url(Images/scriptsSilhouette.png);
+}
+
.panel-enabler-view.scripts img {
content: url(Images/scriptsSilhouette.png);
}
@@ -2930,6 +2953,14 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches {
height: 100%;
}
+.profile-view .data-grid th.average-column {
+ text-align: center;
+}
+
+.profile-view .data-grid td.average-column {
+ text-align: right;
+}
+
.profile-view .data-grid th.self-column {
text-align: center;
}
diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
index 77d720b..184bb45 100644
--- a/WebCore/inspector/front-end/inspector.html
+++ b/WebCore/inspector/front-end/inspector.html
@@ -73,6 +73,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<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>
</head>
<body class="detached">
diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js
index 90ffa2b..9d5bac0 100644
--- a/WebCore/inspector/front-end/inspector.js
+++ b/WebCore/inspector/front-end/inspector.js
@@ -41,7 +41,7 @@ var Preferences = {
}
var WebInspector = {
- resources: [],
+ resources: {},
resourceURLMap: {},
missingLocalizedStrings: {},
@@ -279,22 +279,24 @@ WebInspector.loaded = function()
document.body.addStyleClass("platform-" + platform);
this.console = new WebInspector.Console();
- this.panels = {
- elements: new WebInspector.ElementsPanel(),
- resources: new WebInspector.ResourcesPanel(),
- scripts: new WebInspector.ScriptsPanel(),
- profiles: new WebInspector.ProfilesPanel(),
- databases: new WebInspector.DatabasesPanel()
- };
+ this.panels = {};
var hiddenPanels = (InspectorController.hiddenPanels() || "").split(',');
+ if (hiddenPanels.indexOf("elements") === -1)
+ this.panels.elements = new WebInspector.ElementsPanel();
+ if (hiddenPanels.indexOf("resources") === -1)
+ this.panels.resources = new WebInspector.ResourcesPanel();
+ if (hiddenPanels.indexOf("scripts") === -1)
+ this.panels.scripts = new WebInspector.ScriptsPanel();
+ if (hiddenPanels.indexOf("profiles") === -1)
+ this.panels.profiles = new WebInspector.ProfilesPanel();
+ if (hiddenPanels.indexOf("databases") === -1)
+ this.panels.databases = new WebInspector.DatabasesPanel();
var toolbarElement = document.getElementById("toolbar");
var previousToolbarItem = toolbarElement.children[0];
for (var panelName in this.panels) {
- if (hiddenPanels.indexOf(panelName) !== -1)
- continue;
var panel = this.panels[panelName];
var panelToolbarItem = panel.toolbarItem;
panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this));
@@ -387,6 +389,12 @@ var windowLoaded = function()
window.addEventListener("load", windowLoaded, false);
+WebInspector.dispatch = function() {
+ var methodName = arguments[0];
+ var parameters = Array.prototype.slice.call(arguments, 1);
+ WebInspector[methodName].apply(this, parameters);
+}
+
WebInspector.windowUnload = function(event)
{
InspectorController.windowUnloading();
@@ -769,9 +777,18 @@ WebInspector.showDatabasesPanel = function()
this.currentPanel = this.panels.databases;
}
-WebInspector.addResource = function(resource)
+WebInspector.addResource = function(identifier, payload)
{
- this.resources.push(resource);
+ var resource = new WebInspector.Resource(
+ payload.requestHeaders,
+ payload.requestURL,
+ payload.host,
+ payload.path,
+ payload.lastPathComponent,
+ identifier,
+ payload.isMainResource,
+ payload.cached);
+ this.resources[identifier] = resource;
this.resourceURLMap[resource.url] = resource;
if (resource.mainResource) {
@@ -783,27 +800,101 @@ WebInspector.addResource = function(resource)
this.panels.resources.addResource(resource);
}
-WebInspector.removeResource = function(resource)
+WebInspector.updateResource = function(identifier, payload)
{
+ var resource = this.resources[identifier];
+ if (!resource)
+ return;
+
+ if (payload.didRequestChange) {
+ resource.url = payload.url;
+ resource.domain = payload.domain;
+ resource.path = payload.path;
+ resource.lastPathComponent = payload.lastPathComponent;
+ resource.requestHeaders = payload.requestHeaders;
+ resource.mainResource = payload.mainResource;
+ }
+
+ if (payload.didResponseChange) {
+ resource.mimeType = payload.mimeType;
+ resource.suggestedFilename = payload.suggestedFilename;
+ resource.expectedContentLength = payload.expectedContentLength;
+ resource.statusCode = payload.statusCode;
+ resource.suggestedFilename = payload.suggestedFilename;
+ resource.responseHeaders = payload.responseHeaders;
+ }
+
+ if (payload.didTypeChange) {
+ resource.type = payload.type;
+ }
+
+ if (payload.didLengthChange) {
+ resource.contentLength = payload.contentLength;
+ }
+
+ if (payload.didCompletionChange) {
+ resource.failed = payload.failed;
+ resource.finished = payload.finished;
+ }
+
+ if (payload.didTimingChange) {
+ if (payload.startTime)
+ resource.startTime = payload.startTime;
+ if (payload.responseReceivedTime)
+ resource.responseReceivedTime = payload.responseReceivedTime;
+ if (payload.endTime)
+ resource.endTime = payload.endTime;
+ }
+}
+
+WebInspector.removeResource = function(identifier)
+{
+ var resource = this.resources[identifier];
+ if (!resource)
+ return;
+
resource.category.removeResource(resource);
delete this.resourceURLMap[resource.url];
-
- this.resources.remove(resource, true);
+ delete this.resources[identifier];
if (this.panels.resources)
this.panels.resources.removeResource(resource);
}
-WebInspector.addDatabase = function(database)
+WebInspector.addDatabase = function(payload)
{
+ var database = new WebInspector.Database(
+ payload.database,
+ payload.domain,
+ payload.name,
+ payload.version);
this.panels.databases.addDatabase(database);
}
-WebInspector.addDOMStorage = function(domStorage)
+WebInspector.addDOMStorage = function(payload)
{
+ var domStorage = new WebInspector.DOMStorage(
+ payload.domStorage,
+ payload.host,
+ payload.isLocalStorage);
this.panels.databases.addDOMStorage(domStorage);
}
+WebInspector.resourceTrackingWasEnabled = function()
+{
+ this.panels.resources.resourceTrackingWasEnabled();
+}
+
+WebInspector.resourceTrackingWasDisabled = function()
+{
+ this.panels.resources.resourceTrackingWasDisabled();
+}
+
+WebInspector.attachDebuggerWhenShown = function()
+{
+ this.panels.scripts.attachDebuggerWhenShown();
+}
+
WebInspector.debuggerWasEnabled = function()
{
this.panels.scripts.debuggerWasEnabled();
@@ -839,6 +930,11 @@ WebInspector.pausedScript = function()
this.panels.scripts.debuggerPaused();
}
+WebInspector.resumedScript = function()
+{
+ this.panels.scripts.debuggerResumed();
+}
+
WebInspector.populateInterface = function()
{
for (var panelName in this.panels) {
@@ -859,7 +955,7 @@ WebInspector.reset = function()
for (var category in this.resourceCategories)
this.resourceCategories[category].removeAllResources();
- this.resources = [];
+ this.resources = {};
this.resourceURLMap = {};
this.hoveredDOMNode = null;
@@ -879,9 +975,17 @@ WebInspector.resourceURLChanged = function(resource, oldURL)
this.resourceURLMap[resource.url] = resource;
}
-WebInspector.addMessageToConsole = function(msg)
+WebInspector.addMessageToConsole = function(payload)
{
- this.console.addMessage(msg);
+ var consoleMessage = new WebInspector.ConsoleMessage(
+ payload.source,
+ payload.level,
+ payload.line,
+ payload.url,
+ payload.groupLevel,
+ payload.repeatCount);
+ consoleMessage.setMessageBody(Array.prototype.slice.call(arguments, 1));
+ this.console.addMessage(consoleMessage);
}
WebInspector.addProfile = function(profile)
@@ -1256,6 +1360,7 @@ WebInspector.MIMETypes = {
"image/png": {2: true},
"image/gif": {2: true},
"image/bmp": {2: true},
+ "image/vnd.microsoft.icon": {2: true},
"image/x-icon": {2: true},
"image/x-xbitmap": {2: true},
"font/ttf": {3: true},
diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js
index 7b0a20b..8fb50e2 100644
--- a/WebCore/inspector/front-end/utilities.js
+++ b/WebCore/inspector/front-end/utilities.js
@@ -962,10 +962,11 @@ function indexOfObjectInListSortedByFunction(anObject, aList, aFunction)
else if (c < 0)
last = mid - 1;
else {
- //we return the first occurance of an item in the list.
+ // Return the first occurance of an item in the list.
while (mid > 0 && aFunction(anObject, aList[mid - 1]) === 0)
mid--;
- return mid;
+ first = mid;
+ break;
}
}