From 712bbc24c89f79d263ec0b4dfd01fa163d8f1121 Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Tue, 15 Oct 2019 19:21:51 +0000 Subject: [PATCH] DevTools [Common - Flame Chart]: Making flame chart keyboard accessible in memory and javaScript profiler tool Changes: - Adding keyboard navigability to JavaScript and Memory profiling flame charts - CPUProfileNodes with source links are enter-clickable - Flamechart's focused CPUProfileNodes will turn gray (from blue) when flamechart loses focus CPUProfileNode selected (with and without focus): https://imgur.com/a/e6JkqYW Bug: 963183 Change-Id: Icb00d5b53dab6cd5f83e5602a7d3834afdb7eab3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1663021 Reviewed-by: Yang Guo Reviewed-by: Peter Marshall Commit-Queue: Michael Liao Cr-Original-Commit-Position: refs/heads/master@{#706043} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: a1aacaa1986acbc5a4fe46ef129c6c4dcfeaf28f --- front_end/perf_ui/FlameChart.js | 16 ++++++++++++- front_end/perf_ui/flameChart.css | 4 ++++ front_end/profiler/CPUProfileFlameChart.js | 24 +++++++++++++++++++- front_end/profiler/ProfileView.js | 4 ++-- front_end/profiler/ProfilesPanel.js | 1 - front_end/timeline/TimelineFlameChartView.js | 2 ++ 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/front_end/perf_ui/FlameChart.js b/front_end/perf_ui/FlameChart.js index 4358145083..f65970690c 100644 --- a/front_end/perf_ui/FlameChart.js +++ b/front_end/perf_ui/FlameChart.js @@ -100,6 +100,13 @@ PerfUI.FlameChart = class extends UI.VBox { this._markerHighlighElement = this._viewportElement.createChild('div', 'flame-chart-marker-highlight-element'); this._highlightElement = this._viewportElement.createChild('div', 'flame-chart-highlight-element'); this._selectedElement = this._viewportElement.createChild('div', 'flame-chart-selected-element'); + this._canvas.addEventListener('focus', () => { + this._selectedElement.classList.remove('flame-chart-unfocused-selected-element'); + this.dispatchEventToListeners(PerfUI.FlameChart.Events.CanvasFocused); + }, false); + this._canvas.addEventListener('blur', () => { + this._selectedElement.classList.add('flame-chart-unfocused-selected-element'); + }, false); UI.installDragHandle( this._viewportElement, this._startDragging.bind(this), this._dragging.bind(this), this._endDragging.bind(this), @@ -447,7 +454,7 @@ PerfUI.FlameChart = class extends UI.VBox { this._chartViewport.setRangeSelection(start, end); } else { this._chartViewport.onClick(event); - this.dispatchEventToListeners(PerfUI.FlameChart.Events.EntrySelected, this._highlightedEntryIndex); + this.dispatchEventToListeners(PerfUI.FlameChart.Events.EntryInvoked, this._highlightedEntryIndex); } } @@ -770,6 +777,11 @@ PerfUI.FlameChart = class extends UI.VBox { this.dispatchEventToListeners(PerfUI.FlameChart.Events.EntrySelected, levelIndexes[indexOnLevel]); return true; } + if (isEnterKey(e)) { + e.consume(true); + this.dispatchEventToListeners(PerfUI.FlameChart.Events.EntryInvoked, this._selectedEntryIndex); + return true; + } return false; } @@ -2244,6 +2256,8 @@ PerfUI.FlameChartMarker.prototype = { /** @enum {symbol} */ PerfUI.FlameChart.Events = { + CanvasFocused: Symbol('CanvasFocused'), + EntryInvoked: Symbol('EntryInvoked'), EntrySelected: Symbol('EntrySelected'), EntryHighlighted: Symbol('EntryHighlighted') }; diff --git a/front_end/perf_ui/flameChart.css b/front_end/perf_ui/flameChart.css index d4dfb43f50..4d9c03a2d4 100644 --- a/front_end/perf_ui/flameChart.css +++ b/front_end/perf_ui/flameChart.css @@ -36,6 +36,10 @@ background-color: rgba(56, 121, 217, 0.1); } +.flame-chart-unfocused-selected-element { + outline: 2px solid rgba(123, 123, 123, 1); +} + .chart-cursor-element { position: absolute; top: 0; diff --git a/front_end/profiler/CPUProfileFlameChart.js b/front_end/profiler/CPUProfileFlameChart.js index 3d24520d68..36a227d75c 100644 --- a/front_end/profiler/CPUProfileFlameChart.js +++ b/front_end/profiler/CPUProfileFlameChart.js @@ -215,6 +215,9 @@ Profiler.CPUProfileFlameChart = class extends UI.VBox { this._mainPane.setTextPadding(2); this._mainPane.show(this.element); this._mainPane.addEventListener(PerfUI.FlameChart.Events.EntrySelected, this._onEntrySelected, this); + this._mainPane.addEventListener(PerfUI.FlameChart.Events.EntryInvoked, this._onEntryInvoked, this); + this._entrySelected = false; + this._mainPane.addEventListener(PerfUI.FlameChart.Events.CanvasFocused, this._onEntrySelected, this); this._overviewPane.addEventListener(PerfUI.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this); this._dataProvider = dataProvider; this._searchResults = []; @@ -248,7 +251,26 @@ Profiler.CPUProfileFlameChart = class extends UI.VBox { * @param {!Common.Event} event */ _onEntrySelected(event) { - this.dispatchEventToListeners(PerfUI.FlameChart.Events.EntrySelected, event.data); + if (event.data) { + const eventIndex = Number(event.data); + this._mainPane.setSelectedEntry(eventIndex); + if (eventIndex === -1) { + this._entrySelected = false; + } else { + this._entrySelected = true; + } + } else if (!this._entrySelected) { + this._mainPane.setSelectedEntry(0); + this._entrySelected = true; + } + } + + /** + * @param {!Common.Event} event + */ + _onEntryInvoked(event) { + this._onEntrySelected(event); + this.dispatchEventToListeners(PerfUI.FlameChart.Events.EntryInvoked, event.data); } update() { diff --git a/front_end/profiler/ProfileView.js b/front_end/profiler/ProfileView.js index 6cd4489b42..3f74445b6f 100644 --- a/front_end/profiler/ProfileView.js +++ b/front_end/profiler/ProfileView.js @@ -298,13 +298,13 @@ Profiler.ProfileView = class extends UI.SimpleView { } this._dataProvider = this.createFlameChartDataProvider(); this._flameChart = new Profiler.CPUProfileFlameChart(this._searchableView, this._dataProvider); - this._flameChart.addEventListener(PerfUI.FlameChart.Events.EntrySelected, this._onEntrySelected.bind(this)); + this._flameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked, this._onEntryInvoked.bind(this)); } /** * @param {!Common.Event} event */ - _onEntrySelected(event) { + _onEntryInvoked(event) { const entryIndex = event.data; const node = this._dataProvider._entryNodes[entryIndex]; const debuggerModel = this._profileHeader._debuggerModel; diff --git a/front_end/profiler/ProfilesPanel.js b/front_end/profiler/ProfilesPanel.js index b2b216e60c..78a85082a7 100644 --- a/front_end/profiler/ProfilesPanel.js +++ b/front_end/profiler/ProfilesPanel.js @@ -374,7 +374,6 @@ Profiler.ProfilesPanel = class extends UI.PanelWithSidebar { this.closeVisibleView(); view.show(this.profileViews); - view.focus(); this._toolbarElement.classList.remove('hidden'); this.visibleView = view; diff --git a/front_end/timeline/TimelineFlameChartView.js b/front_end/timeline/TimelineFlameChartView.js index 4c10ef63c4..22ee927994 100644 --- a/front_end/timeline/TimelineFlameChartView.js +++ b/front_end/timeline/TimelineFlameChartView.js @@ -74,7 +74,9 @@ Timeline.TimelineFlameChartView = class extends UI.VBox { this._onMainEntrySelected = this._onEntrySelected.bind(this, this._mainDataProvider); this._onNetworkEntrySelected = this._onEntrySelected.bind(this, this._networkDataProvider); this._mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntrySelected, this._onMainEntrySelected, this); + this._mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked, this._onMainEntrySelected, this); this._networkFlameChart.addEventListener(PerfUI.FlameChart.Events.EntrySelected, this._onNetworkEntrySelected, this); + this._networkFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked, this._onNetworkEntrySelected, this); this._mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryHighlighted, this._onEntryHighlighted, this); this._nextExtensionIndex = 0;