tizen beta release
[framework/web/webkit-efl.git] / debian / libwebkit-engine / usr / share / ewebkit-0 / webinspector / DetailedHeapshotGridNodes.js
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 WebInspector.HeapSnapshotGridNode = function(tree, hasChildren)
32 {
33     WebInspector.DataGridNode.call(this, null, hasChildren);
34     this._defaultPopulateCount = tree._defaultPopulateCount;
35     this._provider = null;
36     this.addEventListener("populate", this._populate, this);
37 }
38
39 WebInspector.HeapSnapshotGridNode.prototype = {
40     createCell: function(columnIdentifier)
41     {
42         var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
43         if (this._searchMatched)
44             cell.addStyleClass("highlight");
45         return cell;
46     },
47
48     dispose: function()
49     {
50         if (this._provider)
51             this._provider.dispose();
52         for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true))
53             if (node.dispose)
54                 node.dispose();
55     },
56
57     hasHoverMessage: false,
58
59     queryObjectContent: function(callback)
60     {
61     },
62
63     _populate: function(event)
64     {
65         this.removeEventListener("populate", this._populate, this);
66         function sorted(ignored)
67         {
68             this.populateChildren();
69         }
70         this._provider.sortAndRewind(this.comparator(), sorted.bind(this));
71     },
72
73     populateChildren: function(provider, howMany, atIndex, afterPopulate, suppressNotifyAboutCompletion)
74     {
75         if (!howMany && provider) {
76             howMany = provider.instanceCount;
77             provider.instanceCount = 0;
78         }
79         provider = provider || this._provider;
80         if (!("instanceCount" in provider))
81             provider.instanceCount = 0;
82         howMany = howMany || this._defaultPopulateCount;
83         atIndex = atIndex || this.children.length;
84         var haveSavedChildren = !!this._savedChildren;
85         if (haveSavedChildren) {
86             haveSavedChildren = false;
87             for (var c in this._savedChildren) {
88                 haveSavedChildren = true;
89                 break;
90             }
91         }
92
93         var part = 0;
94         function callSerialize()
95         {
96             if (part >= howMany)
97                 return;
98             part += this._defaultPopulateCount;
99             provider.serializeNextItems(this._defaultPopulateCount, childrenRetrieved.bind(this));
100         }
101         function childrenRetrieved(items)
102         {
103             var length = items.totalLength;
104             for (var i = 0, l = items.length; i < l; ++i) {
105                 var item = items[i];
106                 if (haveSavedChildren) {
107                     var hash = this._childHashForEntity(item);
108                     if (hash in this._savedChildren) {
109                         this.insertChild(this._savedChildren[hash], atIndex++);
110                         continue;
111                     }
112                 }
113                 this.insertChild(this._createChildNode(item, provider), atIndex++);
114             }
115             provider.instanceCount += items.length;
116             if (part < howMany) {
117                 setTimeout(callSerialize.bind(this), 0);
118                 return;
119             }
120
121             if (items.hasNext)
122                 this.insertChild(new WebInspector.ShowMoreDataGridNode(this.populateChildren.bind(this, provider), this._defaultPopulateCount, length), atIndex++);
123             if (afterPopulate)
124                 afterPopulate();
125             if (!suppressNotifyAboutCompletion) {
126                 function notify()
127                 {
128                     this.dispatchEventToListeners("populate complete");
129                 }
130                 setTimeout(notify.bind(this), 0);
131             }
132         }
133         setTimeout(callSerialize.bind(this), 0);
134     },
135
136     _saveChildren: function()
137     {
138         this._savedChildren = {};
139         for (var i = 0, childrenCount = this.children.length; i < childrenCount; ++i) {
140             var child = this.children[i];
141             if (child.expanded)
142                 this._savedChildren[this._childHashForNode(child)] = child;
143         }
144     },
145
146     sort: function()
147     {
148         this.dataGrid.recursiveSortingEnter();
149         function afterSort(sorted)
150         {
151             if (!sorted) {
152                 this.dataGrid.recursiveSortingLeave();
153                 return;
154             }
155             this._saveChildren();
156             this.removeChildren();
157
158             function afterPopulate()
159             {
160                 for (var i = 0, l = this.children.length; i < l; ++i) {
161                     var child = this.children[i];
162                     if (child.expanded)
163                         child.sort();
164                 }
165                 this.dataGrid.recursiveSortingLeave();
166             }
167             this.populateChildren(this._provider, null, null, afterPopulate.bind(this));
168         }
169         this._provider.sortAndRewind(this.comparator(), afterSort.bind(this));
170     }
171 };
172
173 WebInspector.HeapSnapshotGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
174
175 WebInspector.HeapSnapshotGenericObjectNode = function(tree, node)
176 {
177     WebInspector.HeapSnapshotGridNode.call(this, tree, false);
178     this._name = node.name;
179     this._type = node.type;
180     this._shallowSize = node.selfSize;
181     this._retainedSize = node.retainedSize;
182     this.snapshotNodeId = node.id;
183     this.snapshotNodeIndex = node.nodeIndex;
184     if (this._type === "string")
185         this.hasHoverMessage = true;
186     else if (this._type === "object" && this.isDOMWindow(this._name)) {
187         this._name = this.shortenWindowURL(this._name, false);
188         this.hasHoverMessage = true;
189     } else if (node.flags & tree.snapshot.nodeFlags.canBeQueried)
190         this.hasHoverMessage = true;
191 };
192
193 WebInspector.HeapSnapshotGenericObjectNode.prototype = {
194     createCell: function(columnIdentifier)
195     {
196         var cell = columnIdentifier !== "object" ? WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier) : this._createObjectCell();
197         if (this._searchMatched)
198             cell.addStyleClass("highlight");
199         return cell;
200     },
201
202     _createObjectCell: function()
203     {
204         var cell = document.createElement("td");
205         cell.className = "object-column";
206         var div = document.createElement("div");
207         div.className = "source-code event-properties";
208         div.style.overflow = "hidden";
209         var data = this.data["object"];
210         if (this._prefixObjectCell)
211             this._prefixObjectCell(div, data);
212         var valueSpan = document.createElement("span");
213         valueSpan.className = "value console-formatted-" + data.valueStyle;
214         valueSpan.textContent = data.value;
215         div.appendChild(valueSpan);
216         cell.appendChild(div);
217         cell.addStyleClass("disclosure");
218         if (this.depth)
219             cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
220         return cell;
221     },
222
223     get _countPercent()
224     {
225         return this._count / this.dataGrid.snapshot.nodeCount * 100.0;
226     },
227
228     get data()
229     {
230         var data = this._emptyData();
231
232         var value = this._name;
233         var valueStyle = "object";
234         switch (this._type) {
235         case "string":
236             value = "\"" + value + "\"";
237             valueStyle = "string";
238             break;
239         case "regexp":
240             value = "/" + value + "/";
241             valueStyle = "string";
242             break;
243         case "closure":
244             value = "function " + value + "()";
245             valueStyle = "function";
246             break;
247         case "number":
248             valueStyle = "number";
249             break;
250         case "hidden":
251             valueStyle = "null";
252             break;
253         case "array":
254             if (!value)
255                 value = "[]";
256             else
257                 value += " []";
258             break;
259         };
260         if (this.hasHoverMessage)
261             valueStyle += " highlight";
262         data["object"] = { valueStyle: valueStyle, value: value + " @" + this.snapshotNodeId };
263
264         var view = this.dataGrid.snapshotView;
265         data["shallowSize"] = view.showShallowSizeAsPercent ? WebInspector.UIString("%.2f%%", this._shallowSizePercent) : Number.bytesToString(this._shallowSize);
266         data["retainedSize"] = view.showRetainedSizeAsPercent ? WebInspector.UIString("%.2f%%", this._retainedSizePercent) : Number.bytesToString(this._retainedSize);
267
268         return this._enhanceData ? this._enhanceData(data) : data;
269     },
270
271     queryObjectContent: function(callback)
272     {
273         if (this._type === "string")
274             callback(WebInspector.RemoteObject.fromPrimitiveValue(this._name));
275         else {
276             function formatResult(error, object)
277             {
278                 if (!error && object.type)
279                     callback(WebInspector.RemoteObject.fromPayload(object), !!error);
280                 else
281                     callback(WebInspector.RemoteObject.fromPrimitiveValue(WebInspector.UIString("Not available")));
282             }
283             ProfilerAgent.getObjectByHeapObjectId(this.snapshotNodeId, formatResult);
284         }
285     },
286
287     get _retainedSizePercent()
288     {
289         return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
290     },
291
292     get _shallowSizePercent()
293     {
294         return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
295     },
296
297     _updateHasChildren: function()
298     {
299         function isEmptyCallback(isEmpty)
300         {
301             this.hasChildren = !isEmpty;
302         }
303         this._provider.isEmpty(isEmptyCallback.bind(this));
304     },
305
306     isDOMWindow: function(fullName)
307     {
308         return fullName.substr(0, 9) === "DOMWindow";
309     },
310
311     shortenWindowURL: function(fullName, hasObjectId)
312     {
313         var startPos = fullName.indexOf("/");
314         var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
315         if (startPos !== -1 && endPos !== -1) {
316             var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
317             var url = fullURL.trimURL();
318             if (url.length > 40)
319                 url = url.trimMiddle(40);
320             return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
321         } else
322             return fullName;
323     }
324 }
325
326 WebInspector.HeapSnapshotGenericObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype;
327
328 WebInspector.HeapSnapshotObjectNode = function(tree, isFromBaseSnapshot, edge)
329 {
330     WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, edge.node);
331     this._referenceName = edge.name;
332     this._referenceType = edge.type;
333     this._isFromBaseSnapshot = isFromBaseSnapshot;
334     this._provider = this._createProvider(!isFromBaseSnapshot ? tree.snapshot : tree.baseSnapshot, edge.nodeIndex);
335     this._updateHasChildren();
336 }
337
338 WebInspector.HeapSnapshotObjectNode.prototype = {
339     _createChildNode: function(item)
340     {
341         return new WebInspector.HeapSnapshotObjectNode(this.dataGrid, this._isFromBaseSnapshot, item);
342     },
343
344     _createProvider: function(snapshot, nodeIndex)
345     {
346         var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData;
347         return snapshot.createEdgesProvider(
348             nodeIndex,
349             "function(edge) {" +
350             "    return !edge.isInvisible" +
351             "        && (" + showHiddenData + " || (!edge.isHidden && !edge.node.isHidden));" +
352             "}");
353     },
354
355     _childHashForEntity: function(edge)
356     {
357         return edge.type + "#" + edge.name;
358     },
359
360     _childHashForNode: function(childNode)
361     {
362         return childNode._referenceType + "#" + childNode._referenceName;
363     },
364
365     comparator: function()
366     {
367         var sortAscending = this.dataGrid.sortOrder === "ascending";
368         var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
369         var sortFields = {
370             object: ["!edgeName", sortAscending, "retainedSize", false],
371             count: ["!edgeName", true, "retainedSize", false],
372             shallowSize: ["selfSize", sortAscending, "!edgeName", true],
373             retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
374         }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
375         return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
376     },
377
378     _emptyData: function()
379     {
380         return {count:"", addedCount: "", removedCount: "", countDelta:"", addedSize: "", removedSize: "", sizeDelta: ""};
381     },
382
383     _enhanceData: function(data)
384     {
385         var name = this._referenceName;
386         if (name === "") name = "(empty)";
387         var nameClass = "name";
388         switch (this._referenceType) {
389         case "context":
390             nameClass = "console-formatted-number";
391             break;
392         case "internal":
393         case "hidden":
394             nameClass = "console-formatted-null";
395             break;
396         }
397         data["object"].nameClass = nameClass;
398         data["object"].name = name;
399         return data;
400     },
401
402     _prefixObjectCell: function(div, data)
403     {
404         var nameSpan = document.createElement("span");
405         nameSpan.className = data.nameClass;
406         nameSpan.textContent = data.name;
407         var separatorSpan = document.createElement("span");
408         separatorSpan.className = "separator";
409         separatorSpan.textContent = ": ";
410         div.appendChild(nameSpan);
411         div.appendChild(separatorSpan);
412     }
413 }
414
415 WebInspector.HeapSnapshotObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype;
416
417 WebInspector.HeapSnapshotInstanceNode = function(tree, baseSnapshot, snapshot, node)
418 {
419     WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
420     this._isDeletedNode = !!baseSnapshot;
421     this._provider = this._createProvider(baseSnapshot || snapshot, node.nodeIndex);
422     this._updateHasChildren();
423 };
424
425 WebInspector.HeapSnapshotInstanceNode.prototype = {
426     _createChildNode: function(item)
427     {
428         return new WebInspector.HeapSnapshotObjectNode(this.dataGrid, this._isDeletedNode, item);
429     },
430
431     _createProvider: function(snapshot, nodeIndex)
432     {
433         var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData;
434         return snapshot.createEdgesProvider(
435             nodeIndex,
436             "function(edge) {" +
437             "    return !edge.isInvisible" +
438             "        && (" + showHiddenData + " || (!edge.isHidden && !edge.node.isHidden));" +
439             "}");
440     },
441
442     _childHashForEntity: function(edge)
443     {
444         return edge.type + "#" + edge.name;
445     },
446
447     _childHashForNode: function(childNode)
448     {
449         return childNode._referenceType + "#" + childNode._referenceName;
450     },
451
452     comparator: function()
453     {
454         var sortAscending = this.dataGrid.sortOrder === "ascending";
455         var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
456         var sortFields = {
457             object: ["!edgeName", sortAscending, "retainedSize", false],
458             count: ["!edgeName", true, "retainedSize", false],
459             addedSize: ["selfSize", sortAscending, "!edgeName", true],
460             removedSize: ["selfSize", sortAscending, "!edgeName", true],
461             shallowSize: ["selfSize", sortAscending, "!edgeName", true],
462             retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
463         }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
464         return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
465     },
466
467     _emptyData: function()
468     {
469         return {count:"", countDelta:"", sizeDelta: ""};
470     },
471
472     _enhanceData: function(data)
473     {
474         if (this._isDeletedNode) {
475             data["addedCount"] = "";
476             data["addedSize"] = "";
477             data["removedCount"] = "\u2022";
478             data["removedSize"] = Number.bytesToString(this._shallowSize);
479         } else {
480             data["addedCount"] = "\u2022";
481             data["addedSize"] = Number.bytesToString(this._shallowSize);
482             data["removedCount"] = "";
483             data["removedSize"] = "";
484         }
485         return data;
486     },
487
488     get isDeletedNode()
489     {
490         return this._isDeletedNode;
491     }
492 }
493
494 WebInspector.HeapSnapshotInstanceNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype;
495
496 WebInspector.HeapSnapshotConstructorNode = function(tree, className, aggregate, aggregatesKey)
497 {
498     WebInspector.HeapSnapshotGridNode.call(this, tree, aggregate.count > 0);
499     this._name = className;
500     this._count = aggregate.count;
501     this._shallowSize = aggregate.self;
502     this._retainedSize = aggregate.maxRet;
503     this._provider = this._createNodesProvider(tree.snapshot, className, aggregatesKey);
504 }
505
506 WebInspector.HeapSnapshotConstructorNode.prototype = {
507     _createChildNode: function(item)
508     {
509         return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, null, this.dataGrid.snapshot, item);
510     },
511
512     _createNodesProvider: function(snapshot, className, aggregatesKey)
513     {
514         return snapshot.createNodesProviderForClass(className, aggregatesKey);
515     },
516
517     comparator: function()
518     {
519         var sortAscending = this.dataGrid.sortOrder === "ascending";
520         var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
521         var sortFields = {
522             object: ["id", sortAscending, "retainedSize", false],
523             count: ["id", true, "retainedSize", false],
524             shallowSize: ["selfSize", sortAscending, "id", true],
525             retainedSize: ["retainedSize", sortAscending, "id", true]
526         }[sortColumnIdentifier];
527         return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
528     },
529
530     _childHashForEntity: function(node)
531     {
532         return node.id;
533     },
534
535     _childHashForNode: function(childNode)
536     {
537         return childNode.snapshotNodeId;
538     },
539
540     get data()
541     {
542         var data = {object: this._name, count: this._count};
543         var view = this.dataGrid.snapshotView;
544         data["count"] = view.showCountAsPercent ? WebInspector.UIString("%.2f%%", this._countPercent) : this._count;
545         data["shallowSize"] = view.showShallowSizeAsPercent ? WebInspector.UIString("%.2f%%", this._shallowSizePercent) : Number.bytesToString(this._shallowSize);
546         data["retainedSize"] = "> " + (view.showRetainedSizeAsPercent ? WebInspector.UIString("%.2f%%", this._retainedSizePercent) : Number.bytesToString(this._retainedSize));
547         return data;
548     },
549
550     get _countPercent()
551     {
552         return this._count / this.dataGrid.snapshot.nodeCount * 100.0;
553     },
554
555     get _retainedSizePercent()
556     {
557         return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0;
558     },
559
560     get _shallowSizePercent()
561     {
562         return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0;
563     }
564 };
565
566 WebInspector.HeapSnapshotConstructorNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype;
567
568 WebInspector.HeapSnapshotIteratorsTuple = function(it1, it2)
569 {
570     this._it1 = it1;
571     this._it2 = it2;
572 }
573
574 WebInspector.HeapSnapshotIteratorsTuple.prototype = {
575     dispose: function()
576     {
577         this._it1.dispose();
578         this._it2.dispose();
579     },
580
581     sortAndRewind: function(comparator, callback)
582     {
583         function afterSort(ignored)
584         {
585             this._it2.sortAndRewind(comparator, callback);
586         }
587         this._it1.sortAndRewind(comparator, afterSort.bind(this));
588     }
589 };
590
591 WebInspector.HeapSnapshotDiffNode = function(tree, className, baseAggregate, aggregate)
592 {
593     WebInspector.HeapSnapshotGridNode.call(this, tree, true);
594     this._name = className;
595     this._baseIndexes = baseAggregate ? baseAggregate.idxs : [];
596     this._indexes = aggregate ? aggregate.idxs : [];
597     this._provider = this._createNodesProvider(tree.baseSnapshot, tree.snapshot, aggregate ? aggregate.type : baseAggregate.type, className);
598 }
599
600 WebInspector.HeapSnapshotDiffNode.prototype = {
601     calculateDiff: function(dataGrid, callback)
602     {
603         var diff = dataGrid.snapshot.createDiff(this._name);
604
605         function diffCalculated(diffResult)
606         {
607             diff.dispose();
608             this._addedCount = diffResult.addedCount;
609             this._removedCount = diffResult.removedCount;
610             this._countDelta = diffResult.countDelta;
611             this._addedSize = diffResult.addedSize;
612             this._removedSize = diffResult.removedSize;
613             this._sizeDelta = diffResult.sizeDelta;
614             this._baseIndexes = null;
615             this._indexes = null;
616             callback(this._addedSize === 0 && this._removedSize === 0);
617         }
618         function baseSelfSizesReceived(baseSelfSizes)
619         {
620             diff.pushBaseSelfSizes(baseSelfSizes);
621             diff.calculate(diffCalculated.bind(this));
622         }
623         function baseIdsReceived(baseIds)
624         {
625             diff.pushBaseIds(baseIds);
626             dataGrid.snapshot.pushBaseIds(dataGrid.baseSnapshot.uid, this._name, baseIds);
627             dataGrid.baseSnapshot.nodeFieldValuesByIndex("selfSize", this._baseIndexes, baseSelfSizesReceived.bind(this));
628         }
629         function idsReceived(ids)
630         {
631             dataGrid.baseSnapshot.pushBaseIds(dataGrid.snapshot.uid, this._name, ids);
632         }
633         dataGrid.baseSnapshot.nodeFieldValuesByIndex("id", this._baseIndexes, baseIdsReceived.bind(this));
634         dataGrid.snapshot.nodeFieldValuesByIndex("id", this._indexes, idsReceived.bind(this));
635     },
636
637     _createChildNode: function(item, provider)
638     {
639         if (provider === this._provider._it1)
640             return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, null, provider.snapshot, item);
641         else
642             return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, provider.snapshot, null, item);
643     },
644
645     _createNodesProvider: function(baseSnapshot, snapshot, nodeType, nodeClassName)
646     {
647         var className = this._name;
648         return new WebInspector.HeapSnapshotIteratorsTuple(
649             createProvider(snapshot, baseSnapshot), createProvider(baseSnapshot, snapshot));
650
651         function createProvider(snapshot, otherSnapshot)
652         {
653             var otherSnapshotId = otherSnapshot.uid;
654             var provider = snapshot.createNodesProvider(
655                 "function (node) {" +
656                 "     return node.type === \"" + nodeType + "\" " +
657                 (nodeClassName !== null ? "&& node.className === \"" + nodeClassName + "\"" : "") +
658                 "         && !this.baseSnapshotHasNode(" + otherSnapshotId + ", \"" + className + "\", node.id);" +
659                 "}");
660             provider.snapshot = snapshot;
661             return provider;
662         }
663     },
664
665     _childHashForEntity: function(node)
666     {
667         return node.id;
668     },
669
670     _childHashForNode: function(childNode)
671     {
672         return childNode.snapshotNodeId;
673     },
674
675     comparator: function()
676     {
677         var sortAscending = this.dataGrid.sortOrder === "ascending";
678         var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
679         var sortFields = {
680             object: ["id", sortAscending, "selfSize", false],
681             addedCount: ["selfSize", sortAscending, "id", true],
682             removedCount: ["selfSize", sortAscending, "id", true],
683             countDelta: ["selfSize", sortAscending, "id", true],
684             addedSize: ["selfSize", sortAscending, "id", true],
685             removedSize: ["selfSize", sortAscending, "id", true],
686             sizeDelta: ["selfSize", sortAscending, "id", true]
687         }[sortColumnIdentifier];
688         return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
689     },
690
691     populateChildren: function(provider, howMany, atIndex, afterPopulate)
692     {
693         if (!provider && !howMany) {
694             var firstProviderPopulated = function()
695             {
696                 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it2, this._defaultPopulateCount, atIndex, afterPopulate);
697             };
698             WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it1, this._defaultPopulateCount, atIndex, firstProviderPopulated.bind(this), true);
699         } else if (!howMany) {
700             var firstProviderPopulated = function()
701             {
702                 WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it2, null, atIndex, afterPopulate);
703             };
704             WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it1, null, atIndex, firstProviderPopulated.bind(this), true);
705         } else
706             WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, provider, howMany, atIndex, afterPopulate);
707     },
708
709     _signForDelta: function(delta)
710     {
711         if (delta === 0)
712             return "";
713         if (delta > 0)
714             return "+";
715         else
716             return "\u2212";  // Math minus sign, same width as plus.
717     },
718
719     get data()
720     {
721         var data = {object: this._name};
722
723         data["addedCount"] = this._addedCount;
724         data["removedCount"] = this._removedCount;
725         data["countDelta"] = WebInspector.UIString("%s%d", this._signForDelta(this._countDelta), Math.abs(this._countDelta));
726         data["addedSize"] = Number.bytesToString(this._addedSize);
727         data["removedSize"] = Number.bytesToString(this._removedSize);
728         data["sizeDelta"] = WebInspector.UIString("%s%s", this._signForDelta(this._sizeDelta), Number.bytesToString(Math.abs(this._sizeDelta)));
729
730         return data;
731     }
732 };
733
734 WebInspector.HeapSnapshotDiffNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype;
735
736 WebInspector.HeapSnapshotDominatorObjectNode = function(tree, node)
737 {
738     WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node);
739     this._provider = this._createProvider(tree.snapshot, node.nodeIndex);
740     this._updateHasChildren();
741 };
742
743 WebInspector.HeapSnapshotDominatorObjectNode.prototype = {
744     _createChildNode: function(item)
745     {
746         return new WebInspector.HeapSnapshotDominatorObjectNode(this.dataGrid, item);
747     },
748
749     _createProvider: function(snapshot, nodeIndex)
750     {
751         var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData;
752         return snapshot.createNodesProviderForDominator(nodeIndex,
753             "function (node) {" +
754             "     return " + showHiddenData + " || !node.isHidden;" +
755             "}");
756     },
757
758     _childHashForEntity: function(node)
759     {
760         return node.id;
761     },
762
763     _childHashForNode: function(childNode)
764     {
765         return childNode.snapshotNodeId;
766     },
767
768     comparator: function()
769     {
770         var sortAscending = this.dataGrid.sortOrder === "ascending";
771         var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
772         var sortFields = {
773             object: ["id", sortAscending, "retainedSize", false],
774             shallowSize: ["selfSize", sortAscending, "id", true],
775             retainedSize: ["retainedSize", sortAscending, "id", true]
776         }[sortColumnIdentifier];
777         return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
778     },
779
780     _emptyData: function()
781     {
782         return {};
783     }
784 };
785
786 WebInspector.HeapSnapshotDominatorObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype;
787
788 function MixInSnapshotNodeFunctions(sourcePrototype, targetPrototype)
789 {
790     targetPrototype._childHashForEntity = sourcePrototype._childHashForEntity;
791     targetPrototype._childHashForNode = sourcePrototype._childHashForNode;
792     targetPrototype.comparator = sourcePrototype.comparator;
793     targetPrototype._createChildNode = sourcePrototype._createChildNode;
794     targetPrototype._createProvider = sourcePrototype._createProvider;
795     targetPrototype.dispose = sourcePrototype.dispose;
796     targetPrototype.populateChildren = sourcePrototype.populateChildren;
797     targetPrototype._saveChildren = sourcePrototype._saveChildren;
798     targetPrototype.sort = sourcePrototype.sort;
799 }