3130b2fc3f898fb15715d36e85912c69b74ccee2
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / CanvasDetailsSidebarPanel.js
1 /*
2  * Copyright (C) 2017 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.CanvasDetailsSidebarPanel = class CanvasDetailsSidebarPanel extends WebInspector.DetailsSidebarPanel
27 {
28     constructor()
29     {
30         super("canvas-details", WebInspector.UIString("Canvas"));
31
32         this.element.classList.add("canvas");
33
34         this._canvas = null;
35         this._node = null;
36     }
37
38     // Public
39
40     inspect(objects)
41     {
42         if (!(objects instanceof Array))
43             objects = [objects];
44
45         this.canvas = objects.find((object) => object instanceof WebInspector.Canvas);
46
47         return !!this._canvas;
48     }
49
50     get canvas()
51     {
52         return this._canvas;
53     }
54
55     set canvas(canvas)
56     {
57         if (canvas === this._canvas)
58             return;
59
60         this._canvas = canvas || null;
61
62         if (this._node) {
63             this._node.removeEventListener(WebInspector.DOMNode.Event.AttributeModified, this._refreshSourceSection, this);
64             this._node.removeEventListener(WebInspector.DOMNode.Event.AttributeRemoved, this._refreshSourceSection, this);
65
66             this._node = null;
67         }
68
69         this.needsLayout();
70     }
71
72     // Protected
73
74     initialLayout()
75     {
76         super.initialLayout();
77
78         this._nameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Name"));
79         this._typeRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Type"));
80
81         let identitySection = new WebInspector.DetailsSection("canvas-details", WebInspector.UIString("Identity"));
82         identitySection.groups = [new WebInspector.DetailsSectionGroup([this._nameRow, this._typeRow])];
83         this.contentView.element.appendChild(identitySection.element);
84
85         this._nodeRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Node"));
86         this._cssCanvasRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("CSS Canvas"));
87         this._widthRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Width"));
88         this._heightRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Height"));
89         this._datachedRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Detached"));
90
91         let sourceSection = new WebInspector.DetailsSection("canvas-source", WebInspector.UIString("Source"));
92         sourceSection.groups = [new WebInspector.DetailsSectionGroup([this._nodeRow, this._cssCanvasRow, this._widthRow, this._heightRow, this._datachedRow])];
93         this.contentView.element.appendChild(sourceSection.element);
94
95         this._attributesDataGridRow = new WebInspector.DetailsSectionDataGridRow(null, WebInspector.UIString("No Attributes"));
96
97         let attributesSection = new WebInspector.DetailsSection("canvas-attributes", WebInspector.UIString("Attributes"));
98         attributesSection.groups = [new WebInspector.DetailsSectionGroup([this._attributesDataGridRow])];
99         this.contentView.element.appendChild(attributesSection.element);
100     }
101
102     layout()
103     {
104         super.layout();
105
106         if (!this._canvas)
107             return;
108
109         this._refreshIdentitySection();
110         this._refreshSourceSection();
111         this._refreshAttributesSection();
112     }
113
114     sizeDidChange()
115     {
116         super.sizeDidChange();
117
118         // FIXME: <https://webkit.org/b/152269> Web Inspector: Convert DetailsSection classes to use View
119         this._attributesDataGridRow.sizeDidChange();
120     }
121
122     // Private
123
124     _refreshIdentitySection()
125     {
126         if (!this._canvas)
127             return;
128
129         this._nameRow.value = this._canvas.displayName;
130         this._typeRow.value = WebInspector.Canvas.displayNameForContextType(this._canvas.contextType);
131     }
132
133     _refreshSourceSection()
134     {
135         if (!this._canvas)
136             return;
137
138         this._nodeRow.value = this._canvas.cssCanvasName ? null : emDash;
139         this._cssCanvasRow.value = this._canvas.cssCanvasName || null;
140         this._widthRow.value = emDash;
141         this._heightRow.value = emDash;
142         this._datachedRow.value = null;
143
144         this._canvas.requestNode((node) => {
145             if (!node)
146                 return;
147
148             if (node !== this._node) {
149                 if (this._node) {
150                     this._node.removeEventListener(WebInspector.DOMNode.Event.AttributeModified, this._refreshSourceSection, this);
151                     this._node.removeEventListener(WebInspector.DOMNode.Event.AttributeRemoved, this._refreshSourceSection, this);
152
153                     this._node = null;
154                 }
155
156                 this._node = node;
157
158                 this._node.addEventListener(WebInspector.DOMNode.Event.AttributeModified, this._refreshSourceSection, this);
159                 this._node.addEventListener(WebInspector.DOMNode.Event.AttributeRemoved, this._refreshSourceSection, this);
160             }
161
162             if (!this._canvas.cssCanvasName)
163                 this._nodeRow.value = WebInspector.linkifyNodeReference(this._node);
164
165             let setRowValueIfValidAttributeValue = (row, attribute) => {
166                 let value = Number(this._node.getAttribute(attribute));
167                 if (!Number.isInteger(value) || value < 0)
168                     return false;
169
170                 row.value = value;
171                 return true;
172             };
173
174             let validWidth = setRowValueIfValidAttributeValue(this._widthRow, "width");
175             let validHeight = setRowValueIfValidAttributeValue(this._heightRow, "height");
176             if (!validWidth || !validHeight) {
177                 // Since the "width" and "height" properties of canvas elements are more than just
178                 // attributes, we need to invoke the getter for each to get the actual value.
179                 //  - https://html.spec.whatwg.org/multipage/canvas.html#attr-canvas-width
180                 //  - https://html.spec.whatwg.org/multipage/canvas.html#attr-canvas-height
181                 WebInspector.RemoteObject.resolveNode(node, "", (remoteObject) => {
182                     if (!remoteObject)
183                         return;
184
185                     function setRowValueToPropertyValue(row, property) {
186                         remoteObject.getProperty(property, (error, result, wasThrown) => {
187                             if (!error && result.type === "number")
188                                 row.value = `${result.value}px`;
189                         });
190                     }
191
192                     setRowValueToPropertyValue(this._widthRow, "width");
193                     setRowValueToPropertyValue(this._heightRow, "height");
194
195                     remoteObject.release();
196                 });
197             }
198
199             if (!this._canvas.cssCanvasName && !this._node.parentNode)
200                 this._datachedRow.value = WebInspector.UIString("Yes");
201         });
202     }
203
204     _refreshAttributesSection()
205     {
206         if (!this._canvas)
207             return;
208
209         if (isEmptyObject(this._canvas.contextAttributes)) {
210             // Remove the DataGrid to show the placeholder text.
211             this._attributesDataGridRow.dataGrid = null;
212             return;
213         }
214
215         let dataGrid = this._attributesDataGridRow.dataGrid;
216         if (!dataGrid) {
217             dataGrid = this._attributesDataGridRow.dataGrid = new WebInspector.DataGrid({
218                 name: {title: WebInspector.UIString("Name")},
219                 value: {title: WebInspector.UIString("Value"), width: "30%"},
220             });
221         }
222
223         dataGrid.removeChildren();
224
225         for (let attribute in this._canvas.contextAttributes) {
226             let data = {name: attribute, value: this._canvas.contextAttributes[attribute]};
227             let dataGridNode = new WebInspector.DataGridNode(data);
228             dataGrid.appendChild(dataGridNode);
229         }
230
231         dataGrid.updateLayoutIfNeeded();
232     }
233 };