Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: Source/devtools/front_end/profiler/CanvasReplayStateView.js

Issue 1073863003: DevTools: remove Canvas profiler from DevTools source base. See details in the bug. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: tests gone Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 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 /**
32 * @constructor
33 * @extends {WebInspector.VBox}
34 * @param {!WebInspector.CanvasTraceLogPlayerProxy} traceLogPlayer
35 */
36 WebInspector.CanvasReplayStateView = function(traceLogPlayer)
37 {
38 WebInspector.VBox.call(this);
39 this.registerRequiredCSS("profiler/canvasProfiler.css");
40 this.element.classList.add("canvas-replay-state-view");
41 this._traceLogPlayer = traceLogPlayer;
42
43 var controlsToolbar = new WebInspector.StatusBar(this.element);
44 this._prevButton = this._createControlButton(controlsToolbar, "play-backward s-status-bar-item", WebInspector.UIString("Previous resource."), this._onResourc eNavigationClick.bind(this, false));
45 this._nextButton = this._createControlButton(controlsToolbar, "play-status-b ar-item", WebInspector.UIString("Next resource."), this._onResourceNavigationCli ck.bind(this, true));
46 this._createControlButton(controlsToolbar, "refresh-status-bar-item", WebIns pector.UIString("Refresh."), this._onStateRefreshClick.bind(this));
47
48 this._resourceSelector = new WebInspector.StatusBarComboBox(this._onReplayRe sourceChanged.bind(this));
49 this._currentOption = this._resourceSelector.createOption(WebInspector.UIStr ing("<auto>"), WebInspector.UIString("Show state of the last replayed resource." ), "");
50 controlsToolbar.appendStatusBarItem(this._resourceSelector);
51
52 /** @type {!Object.<string, string>} */
53 this._resourceIdToDescription = {};
54
55 /** @type {!Object.<string, !Object.<string, boolean>>} */
56 this._gridNodesExpandedState = {};
57 /** @type {!Object.<string, !{scrollTop: number, scrollLeft: number}>} */
58 this._gridScrollPositions = {};
59
60 /** @type {?CanvasAgent.ResourceId} */
61 this._currentResourceId = null;
62 /** @type {!Array.<!Element>} */
63 this._prevOptionsStack = [];
64 /** @type {!Array.<!Element>} */
65 this._nextOptionsStack = [];
66
67 /** @type {!Array.<!WebInspector.DataGridNode>} */
68 this._highlightedGridNodes = [];
69
70 var columns = [
71 {title: WebInspector.UIString("Name"), sortable: false, width: "50%", di sclosure: true},
72 {title: WebInspector.UIString("Value"), sortable: false, width: "50%"}
73 ];
74
75 this._stateGrid = new WebInspector.DataGrid(columns);
76 this._stateGrid.element.classList.add("fill");
77 this._stateGrid.show(this.element);
78
79 this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy .Events.CanvasReplayStateChanged, this._onReplayResourceChanged, this);
80 this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy .Events.CanvasTraceLogReceived, this._onCanvasTraceLogReceived, this);
81 this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy .Events.CanvasResourceStateReceived, this._onCanvasResourceStateReceived, this);
82
83 this._updateButtonsEnabledState();
84 }
85
86 WebInspector.CanvasReplayStateView.prototype = {
87 /**
88 * @param {string} resourceId
89 */
90 selectResource: function(resourceId)
91 {
92 if (resourceId === this._resourceSelector.selectedOption().value)
93 return;
94 var option = this._resourceSelector.selectElement().firstChild;
95 for (var index = 0; option; ++index, option = option.nextSibling) {
96 if (resourceId === option.value) {
97 this._resourceSelector.setSelectedIndex(index);
98 this._onReplayResourceChanged();
99 break;
100 }
101 }
102 },
103
104 /**
105 * @param {!WebInspector.StatusBar} toolbar
106 * @param {string} className
107 * @param {string} title
108 * @param {function(this:WebInspector.CanvasProfileView)} clickCallback
109 * @return {!WebInspector.StatusBarButton}
110 */
111 _createControlButton: function(toolbar, className, title, clickCallback)
112 {
113 var button = new WebInspector.StatusBarButton(title, className);
114 toolbar.appendStatusBarItem(button);
115
116 button.makeLongClickEnabled();
117 button.addEventListener("click", clickCallback, this);
118 button.addEventListener("longClickDown", clickCallback, this);
119 button.addEventListener("longClickPress", clickCallback, this);
120 return button;
121 },
122
123 /**
124 * @param {boolean} forward
125 */
126 _onResourceNavigationClick: function(forward)
127 {
128 var newOption = forward ? this._nextOptionsStack.pop() : this._prevOptio nsStack.pop();
129 if (!newOption)
130 return;
131 (forward ? this._prevOptionsStack : this._nextOptionsStack).push(this._c urrentOption);
132 this._isNavigationButton = true;
133 this.selectResource(newOption.value);
134 delete this._isNavigationButton;
135 this._updateButtonsEnabledState();
136 },
137
138 _onStateRefreshClick: function()
139 {
140 this._traceLogPlayer.clearResourceStates();
141 },
142
143 _updateButtonsEnabledState: function()
144 {
145 this._prevButton.setEnabled(this._prevOptionsStack.length > 0);
146 this._nextButton.setEnabled(this._nextOptionsStack.length > 0);
147 },
148
149 _updateCurrentOption: function()
150 {
151 const maxStackSize = 256;
152 var selectedOption = this._resourceSelector.selectedOption();
153 if (this._currentOption === selectedOption)
154 return;
155 if (!this._isNavigationButton) {
156 this._prevOptionsStack.push(this._currentOption);
157 this._nextOptionsStack = [];
158 if (this._prevOptionsStack.length > maxStackSize)
159 this._prevOptionsStack.shift();
160 this._updateButtonsEnabledState();
161 }
162 this._currentOption = selectedOption;
163 },
164
165 /**
166 * @param {!CanvasAgent.TraceLog} traceLog
167 */
168 _collectResourcesFromTraceLog: function(traceLog)
169 {
170 /** @type {!Array.<!CanvasAgent.CallArgument>} */
171 var collectedResources = [];
172 var calls = traceLog.calls;
173 for (var i = 0, n = calls.length; i < n; ++i) {
174 var call = calls[i];
175 var args = call.arguments || [];
176 for (var j = 0; j < args.length; ++j)
177 this._collectResourceFromCallArgument(args[j], collectedResource s);
178 this._collectResourceFromCallArgument(call.result, collectedResource s);
179 this._collectResourceFromCallArgument(call.value, collectedResources );
180 }
181 var contexts = traceLog.contexts;
182 for (var i = 0, n = contexts.length; i < n; ++i)
183 this._collectResourceFromCallArgument(contexts[i], collectedResource s);
184 this._addCollectedResourcesToSelector(collectedResources);
185 },
186
187 /**
188 * @param {!CanvasAgent.ResourceState} resourceState
189 */
190 _collectResourcesFromResourceState: function(resourceState)
191 {
192 /** @type {!Array.<!CanvasAgent.CallArgument>} */
193 var collectedResources = [];
194 this._collectResourceFromResourceStateDescriptors(resourceState.descript ors, collectedResources);
195 this._addCollectedResourcesToSelector(collectedResources);
196 },
197
198 /**
199 * @param {!Array.<!CanvasAgent.ResourceStateDescriptor>|undefined} descript ors
200 * @param {!Array.<!CanvasAgent.CallArgument>} output
201 */
202 _collectResourceFromResourceStateDescriptors: function(descriptors, output)
203 {
204 if (!descriptors)
205 return;
206 for (var i = 0, n = descriptors.length; i < n; ++i) {
207 var descriptor = descriptors[i];
208 this._collectResourceFromCallArgument(descriptor.value, output);
209 this._collectResourceFromResourceStateDescriptors(descriptor.values, output);
210 }
211 },
212
213 /**
214 * @param {!CanvasAgent.CallArgument|undefined} argument
215 * @param {!Array.<!CanvasAgent.CallArgument>} output
216 */
217 _collectResourceFromCallArgument: function(argument, output)
218 {
219 if (!argument)
220 return;
221 var resourceId = argument.resourceId;
222 if (!resourceId || this._resourceIdToDescription[resourceId])
223 return;
224 this._resourceIdToDescription[resourceId] = argument.description;
225 output.push(argument);
226 },
227
228 /**
229 * @param {!Array.<!CanvasAgent.CallArgument>} collectedResources
230 */
231 _addCollectedResourcesToSelector: function(collectedResources)
232 {
233 if (!collectedResources.length)
234 return;
235 /**
236 * @param {!CanvasAgent.CallArgument} arg1
237 * @param {!CanvasAgent.CallArgument} arg2
238 * @return {number}
239 */
240 function comparator(arg1, arg2)
241 {
242 var a = arg1.description;
243 var b = arg2.description;
244 return String.naturalOrderComparator(a, b);
245 }
246 collectedResources.sort(comparator);
247
248 var selectElement = this._resourceSelector.selectElement();
249 var currentOption = selectElement.firstChild;
250 currentOption = currentOption.nextSibling; // Skip the "<auto>" option.
251 for (var i = 0, n = collectedResources.length; i < n; ++i) {
252 var argument = collectedResources[i];
253 while (currentOption && String.naturalOrderComparator(currentOption. text, argument.description) < 0)
254 currentOption = currentOption.nextSibling;
255 var option = this._resourceSelector.createOption(argument.descriptio n, WebInspector.UIString("Show state of this resource."), argument.resourceId);
256 if (currentOption)
257 selectElement.insertBefore(option, currentOption);
258 }
259 },
260
261 _onReplayResourceChanged: function()
262 {
263 this._updateCurrentOption();
264 var selectedResourceId = this._resourceSelector.selectedOption().value;
265
266 /**
267 * @param {?CanvasAgent.ResourceState} resourceState
268 * @this {WebInspector.CanvasReplayStateView}
269 */
270 function didReceiveResourceState(resourceState)
271 {
272 if (selectedResourceId !== this._resourceSelector.selectedOption().v alue)
273 return;
274 this._showResourceState(resourceState);
275 }
276 this._traceLogPlayer.getResourceState(selectedResourceId, didReceiveReso urceState.bind(this));
277 },
278
279 /**
280 * @param {!WebInspector.Event} event
281 */
282 _onCanvasTraceLogReceived: function(event)
283 {
284 var traceLog = /** @type {!CanvasAgent.TraceLog} */ (event.data);
285 console.assert(traceLog);
286 this._collectResourcesFromTraceLog(traceLog);
287 },
288
289 /**
290 * @param {!WebInspector.Event} event
291 */
292 _onCanvasResourceStateReceived: function(event)
293 {
294 var resourceState = /** @type {!CanvasAgent.ResourceState} */ (event.dat a);
295 console.assert(resourceState);
296 this._collectResourcesFromResourceState(resourceState);
297 },
298
299 /**
300 * @param {?CanvasAgent.ResourceState} resourceState
301 */
302 _showResourceState: function(resourceState)
303 {
304 this._saveExpandedState();
305 this._saveScrollState();
306
307 var rootNode = this._stateGrid.rootNode();
308 if (!resourceState) {
309 this._currentResourceId = null;
310 this._updateDataGridHighlights([]);
311 rootNode.removeChildren();
312 return;
313 }
314
315 var nodesToHighlight = [];
316 var nameToOldGridNodes = {};
317
318 /**
319 * @param {!Object} map
320 * @param {!WebInspector.DataGridNode=} node
321 */
322 function populateNameToNodesMap(map, node)
323 {
324 if (!node)
325 return;
326 for (var i = 0, child; child = node.children[i]; ++i) {
327 var item = {
328 node: child,
329 children: {}
330 };
331 map[child.name] = item;
332 populateNameToNodesMap(item.children, child);
333 }
334 }
335 populateNameToNodesMap(nameToOldGridNodes, rootNode);
336 rootNode.removeChildren();
337
338 /**
339 * @param {!CanvasAgent.ResourceStateDescriptor} d1
340 * @param {!CanvasAgent.ResourceStateDescriptor} d2
341 * @return {number}
342 */
343 function comparator(d1, d2)
344 {
345 var hasChildren1 = !!d1.values;
346 var hasChildren2 = !!d2.values;
347 if (hasChildren1 !== hasChildren2)
348 return hasChildren1 ? 1 : -1;
349 return String.naturalOrderComparator(d1.name, d2.name);
350 }
351 /**
352 * @param {!Array.<!CanvasAgent.ResourceStateDescriptor>|undefined} desc riptors
353 * @param {!WebInspector.DataGridNode} parent
354 * @param {!Object=} nameToOldChildren
355 * @this {WebInspector.CanvasReplayStateView}
356 */
357 function appendResourceStateDescriptors(descriptors, parent, nameToOldCh ildren)
358 {
359 descriptors = descriptors || [];
360 descriptors.sort(comparator);
361 var oldChildren = nameToOldChildren || {};
362 for (var i = 0, n = descriptors.length; i < n; ++i) {
363 var descriptor = descriptors[i];
364 var childNode = this._createDataGridNode(descriptor);
365 parent.appendChild(childNode);
366 var oldChildrenItem = oldChildren[childNode.name] || {};
367 var oldChildNode = oldChildrenItem.node;
368 if (!oldChildNode || oldChildNode.element().textContent !== chil dNode.element().textContent)
369 nodesToHighlight.push(childNode);
370 appendResourceStateDescriptors.call(this, descriptor.values, chi ldNode, oldChildrenItem.children);
371 }
372 }
373 appendResourceStateDescriptors.call(this, resourceState.descriptors, roo tNode, nameToOldGridNodes);
374
375 var shouldHighlightChanges = (this._resourceKindId(this._currentResource Id) === this._resourceKindId(resourceState.id));
376 this._currentResourceId = resourceState.id;
377 this._restoreExpandedState();
378 this._updateDataGridHighlights(shouldHighlightChanges ? nodesToHighlight : []);
379 this._restoreScrollState();
380 },
381
382 /**
383 * @param {!Array.<!WebInspector.DataGridNode>} nodes
384 */
385 _updateDataGridHighlights: function(nodes)
386 {
387 for (var i = 0, n = this._highlightedGridNodes.length; i < n; ++i)
388 this._highlightedGridNodes[i].element().classList.remove("canvas-gri d-node-highlighted");
389
390 this._highlightedGridNodes = nodes;
391
392 for (var i = 0, n = this._highlightedGridNodes.length; i < n; ++i) {
393 var node = this._highlightedGridNodes[i];
394 WebInspector.runCSSAnimationOnce(node.element(), "canvas-grid-node-h ighlighted");
395 node.reveal();
396 }
397 },
398
399 /**
400 * @param {?CanvasAgent.ResourceId} resourceId
401 * @return {string}
402 */
403 _resourceKindId: function(resourceId)
404 {
405 var description = (resourceId && this._resourceIdToDescription[resourceI d]) || "";
406 return description.replace(/\d+/g, "");
407 },
408
409 /**
410 * @param {function(!WebInspector.DataGridNode, string):void} callback
411 */
412 _forEachGridNode: function(callback)
413 {
414 /**
415 * @param {!WebInspector.DataGridNode} node
416 * @param {string} key
417 */
418 function processRecursively(node, key)
419 {
420 for (var i = 0, child; child = node.children[i]; ++i) {
421 var childKey = key + "#" + child.name;
422 callback(child, childKey);
423 processRecursively(child, childKey);
424 }
425 }
426 processRecursively(this._stateGrid.rootNode(), "");
427 },
428
429 _saveExpandedState: function()
430 {
431 if (!this._currentResourceId)
432 return;
433 var expandedState = {};
434 var key = this._resourceKindId(this._currentResourceId);
435 this._gridNodesExpandedState[key] = expandedState;
436 /**
437 * @param {!WebInspector.DataGridNode} node
438 * @param {string} key
439 */
440 function callback(node, key)
441 {
442 if (node.expanded)
443 expandedState[key] = true;
444 }
445 this._forEachGridNode(callback);
446 },
447
448 _restoreExpandedState: function()
449 {
450 if (!this._currentResourceId)
451 return;
452 var key = this._resourceKindId(this._currentResourceId);
453 var expandedState = this._gridNodesExpandedState[key];
454 if (!expandedState)
455 return;
456 /**
457 * @param {!WebInspector.DataGridNode} node
458 * @param {string} key
459 */
460 function callback(node, key)
461 {
462 if (expandedState[key])
463 node.expand();
464 }
465 this._forEachGridNode(callback);
466 },
467
468 _saveScrollState: function()
469 {
470 if (!this._currentResourceId)
471 return;
472 var key = this._resourceKindId(this._currentResourceId);
473 this._gridScrollPositions[key] = {
474 scrollTop: this._stateGrid.scrollContainer.scrollTop,
475 scrollLeft: this._stateGrid.scrollContainer.scrollLeft
476 };
477 },
478
479 _restoreScrollState: function()
480 {
481 if (!this._currentResourceId)
482 return;
483 var key = this._resourceKindId(this._currentResourceId);
484 var scrollState = this._gridScrollPositions[key];
485 if (!scrollState)
486 return;
487 this._stateGrid.scrollContainer.scrollTop = scrollState.scrollTop;
488 this._stateGrid.scrollContainer.scrollLeft = scrollState.scrollLeft;
489 },
490
491 /**
492 * @param {!CanvasAgent.ResourceStateDescriptor} descriptor
493 * @return {!WebInspector.DataGridNode}
494 */
495 _createDataGridNode: function(descriptor)
496 {
497 var name = descriptor.name;
498 var callArgument = descriptor.value;
499 var target = this._traceLogPlayer.target();
500
501 /** @type {!Element|string} */
502 var valueElement = callArgument ? WebInspector.CanvasProfileDataGridHelp er.createCallArgumentElement(target, callArgument) : "";
503
504 /** @type {!Element|string} */
505 var nameElement = name;
506 if (target && typeof descriptor.enumValueForName !== "undefined")
507 nameElement = WebInspector.CanvasProfileDataGridHelper.createEnumVal ueElement(target, name, +descriptor.enumValueForName);
508
509 if (descriptor.isArray && descriptor.values) {
510 if (typeof nameElement === "string")
511 nameElement += "[" + descriptor.values.length + "]";
512 else {
513 var element = createElement("span");
514 element.appendChild(nameElement);
515 element.createTextChild("[" + descriptor.values.length + "]");
516 nameElement = element;
517 }
518 }
519
520 var data = {};
521 data[0] = nameElement;
522 data[1] = valueElement;
523 var node = new WebInspector.DataGridNode(data);
524 node.selectable = false;
525 node.name = name;
526 return node;
527 },
528
529 __proto__: WebInspector.VBox.prototype
530 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/profiler/CanvasProfileView.js ('k') | Source/devtools/front_end/profiler/ProfileTypeRegistry.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698