Web Inspector: Modify the type profiler runtime protocol to transfer some computation...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / TypePropertiesSection.js
1 /*
2  * Copyright (C) 2014 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.TypePropertiesSection = function(types, title, subtitle)
27 {
28     this.emptyPlaceholder = WebInspector.UIString("No Properties");
29     this.types = types;
30
31     WebInspector.PropertiesSection.call(this, title, subtitle);
32 };
33
34 WebInspector.TypePropertiesSection.prototype = {
35     constructor: WebInspector.TypePropertiesSection,
36     __proto__: WebInspector.PropertiesSection.prototype,
37
38     onpopulate: function()
39     {
40         this.propertiesTreeOutline.removeChildren();
41
42         var primitiveTypeNames = this.types.primitiveTypeNames;
43         var structures = this.types.structures;
44         var properties = [];
45         for (var struct of structures) {
46             properties.push({
47                 name: struct.constructorName,
48                 structure: struct
49             });
50         }
51         for (var primitiveName of primitiveTypeNames) {
52             properties.push({
53                 name: primitiveName,
54                 structure: null
55             });
56         }
57
58         properties.sort(WebInspector.TypePropertiesSection.PropertyComparator);
59
60         if (this.types.isTruncated)
61             properties.push({name: "\u2026", structure: null});
62
63         for (var property of properties)
64             this.propertiesTreeOutline.appendChild(new WebInspector.TypePropertyTreeElement(property));
65
66         if (!this.propertiesTreeOutline.children.length) {
67             var title = document.createElement("div");
68             title.className = "info";
69             title.textContent = this.emptyPlaceholder;
70             var infoElement = new TreeElement(title, null, false);
71             this.propertiesTreeOutline.appendChild(infoElement);
72         }
73
74         this.dispatchEventToListeners(WebInspector.Section.Event.VisibleContentDidChange);
75
76         if (properties.length === 1)
77             this.propertiesTreeOutline.children[0].expandRecursively();
78     }
79 };
80
81 // This is mostly identical to ObjectPropertiesSection.compareProperties.
82 // But this checks for equality because we can have two objects named the same thing.
83 WebInspector.TypePropertiesSection.PropertyComparator = function(propertyA, propertyB)
84 {
85     var a = propertyA.name;
86     var b = propertyB.name;
87     if (a.indexOf("__proto__") !== -1)
88         return 1;
89     if (b.indexOf("__proto__") !== -1)
90         return -1;
91     if (a === b)
92         return 1;
93
94     var diff = 0;
95     var chunk = /^\d+|^\D+/;
96     var chunka, chunkb, anum, bnum;
97     while (diff === 0) {
98         if (!a && b)
99             return -1;
100         if (!b && a)
101             return 1;
102         chunka = a.match(chunk)[0];
103         chunkb = b.match(chunk)[0];
104         anum = !isNaN(chunka);
105         bnum = !isNaN(chunkb);
106         if (anum && !bnum)
107             return -1;
108         if (bnum && !anum)
109             return 1;
110         if (anum && bnum) {
111             diff = chunka - chunkb;
112             if (diff === 0 && chunka.length !== chunkb.length) {
113                 if (!+chunka && !+chunkb) // chunks are strings of all 0s (special case)
114                     return chunka.length - chunkb.length;
115                 else
116                     return chunkb.length - chunka.length;
117             }
118         } else if (chunka !== chunkb)
119             return (chunka < chunkb) ? -1 : 1;
120         a = a.substring(chunka.length);
121         b = b.substring(chunkb.length);
122     }
123
124     return diff;
125 };
126
127 WebInspector.TypePropertyTreeElement = function(property)
128 {
129     this.property = property;
130
131     this.nameElement = document.createElement("span");
132     this.nameElement.className = "name";
133     this.nameElement.textContent = this.property.name;
134
135     TreeElement.call(this, this.nameElement, null, false);
136
137     this.toggleOnClick = true;
138     this.hasChildren = !!this.property.structure;
139 };
140
141 WebInspector.TypePropertyTreeElement.prototype = {
142     constructor: WebInspector.TypePropertyTreeElement,
143     __proto__: TreeElement.prototype,
144
145     onpopulate: function()
146     {
147         this.removeChildren();
148
149         var properties = [];
150         for (var fieldName of this.property.structure.fields) {
151             properties.push({
152                 name: fieldName,
153                 structure: null
154             });
155         }
156
157         properties.sort(WebInspector.TypePropertiesSection.PropertyComparator);
158
159         for (var property of properties)
160             this.appendChild(new WebInspector.TypePropertyTreeElement(property));
161
162         properties = [];
163         for (var fieldName of this.property.structure.optionalFields) {
164             properties.push({
165                 name: fieldName + "?",
166                 structure: null
167             });
168         }
169
170         properties.sort(WebInspector.TypePropertiesSection.PropertyComparator);
171
172         if (this.property.structure.isImprecise)
173             properties.push({name: "\u2026", structure: null});
174
175         if (this.property.structure.prototypeStructure) {
176             properties.push({
177                 name: this.property.structure.prototypeStructure.constructorName + " (" + WebInspector.UIString("Prototype") + ")",
178                 structure: this.property.structure.prototypeStructure
179             });
180         }
181
182         for (var property of properties)
183             this.appendChild(new WebInspector.TypePropertyTreeElement(property));
184     }
185 };
186