Changeset 223918 in webkit
- Timestamp:
- Oct 24, 2017 1:47:11 PM (7 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 1 deleted
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/.eslintrc
r223308 r223918 79 79 "TestHarness": true, 80 80 "TestSuite": true, 81 "WI": true,82 81 83 82 // Externals -
trunk/Source/WebInspectorUI/ChangeLog
r223914 r223918 1 2017-10-24 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: Show recordings in CanvasTabContentView 4 https://bugs.webkit.org/show_bug.cgi?id=177606 5 <rdar://problem/34715819> 6 7 Reviewed by Brian Burg. 8 9 Original patch by Matt Baker <mattbaker@apple.com>. 10 11 This patch folds canvas recordings into the new Canvas tab, which now 12 supports showing both CanvasCollections and Recordings. 13 14 When viewing recordings, a back button is shown at the start of the 15 navigation bar, allowing the user to return to the overview. It has been 16 styled with a back arrow, to make its function as clear as possible. 17 Like other navigation path components, the item for the recording can 18 clicked to select another recording taken from the same canvas. 19 20 The recording action scrubber has been moved from the content browser's 21 navigation bar to a more prominent location in the recording content view. 22 Selecting a frame tree element in the navigation sidebar no longer selects 23 the last action for that frame. This was changed to prevent the scrubber 24 position from behaving non-monotonically when selecting actions in sequential 25 order. 26 27 While this patch retains support for importing recordings, the feature 28 is not polished. Currently it is not possible to return to an imported 29 recording after leaving closing the view. In the future we may want to 30 consider including a navigation sidebar panel for the overview, which 31 could list canvas recordings (and eventually shaders). 32 33 * .eslintrc: 34 Drive-by: remove duplicate key. 35 36 * Localizations/en.lproj/localizedStrings.js: 37 * UserInterface/Base/Main.js: 38 (WI.contentLoaded): 39 (WI.tabContentViewClassForRepresentedObject): 40 * UserInterface/Main.html: 41 * UserInterface/Views/RecordingTabContentView.js: Removed. 42 Remove RecordingTabContentView. 43 44 * UserInterface/Images/Recording.svg: 45 New recording icon, used for tree elements and canvas preview UI. 46 47 * UserInterface/Models/Recording.js: 48 (WI.Recording): 49 (WI.Recording.prototype.get visualActionIndexes): 50 Visual action indexes should be computed by the recording. 51 52 * UserInterface/Views/CanvasContentView.js: 53 (WI.CanvasContentView): 54 (WI.CanvasContentView.prototype.refresh): 55 (WI.CanvasContentView.prototype.initialLayout): 56 (WI.CanvasContentView.prototype.attached): 57 (WI.CanvasContentView.prototype._recordingStopped): 58 (WI.CanvasContentView.prototype._handleRecordingSelectElementChange): 59 New UI for showing CanvasContentView as a CollectionView item. Includes 60 recordings button and select for choosing a recording to view. 61 62 * UserInterface/Views/CanvasOverviewContentView.css: 63 (.content-view.canvas-overview .content-view.canvas > header): 64 Switch to 13px, which is more frequently used. 65 66 (.content-view.canvas-overview .content-view.canvas > header .subtitle::before): 67 Switch to literal em dash. Surrounding spaces were ignored when using 68 the backslash-escaped character. 69 70 (.content-view.canvas-overview .content-view.canvas:not(:hover, .is-recording, .selected) > header > .navigation-bar): 71 (.content-view.canvas-overview .content-view.canvas > footer > .recordings): 72 (.content-view.canvas-overview .content-view.canvas > footer > .recordings::before): 73 (.content-view.canvas-overview .content-view.canvas > footer > .recordings > select): 74 (.content-view.canvas-overview .content-view.canvas > footer .recordings > select:focus): 75 (.content-view.canvas-overview .content-view.canvas > footer > .flexible-space): 76 (.popover-content > .tree-outline .item.recording > .icon): 77 (.popover-content > .tree-outline .item.recording:hover): 78 (.popover-content > .tree-outline .item.recording:hover > .icon): 79 (.content-view.canvas-overview .content-view.canvas:not(:hover, .is-recording) > header > .navigation-bar): Deleted. 80 (.content-view.canvas-overview .content-view.canvas > footer): Deleted. 81 New styles for the recording picker. 82 83 * UserInterface/Views/CanvasOverviewContentView.js: 84 (WI.CanvasOverviewContentView): 85 (WI.CanvasOverviewContentView.prototype.get selectionPathComponents): 86 (WI.CanvasOverviewContentView.prototype.contentViewAdded): 87 (WI.CanvasOverviewContentView.prototype.contentViewRemoved): 88 (WI.CanvasOverviewContentView.prototype._supplementalRepresentedObjectsDidChange): 89 (WI.CanvasOverviewContentView.prototype._selectedPathComponentChanged): Deleted. 90 (WI.CanvasOverviewContentView.prototype._supplementalRepresentedObjectsDidChange.createCanvasPathComponent): Deleted. 91 Canvas tree elements are now managed by CanvasTabContentView, which is 92 now responsible for maintaining the tree of canvas objects. For now the 93 tree holds canvases and recordings, but will eventually include shader programs. 94 95 * UserInterface/Views/CanvasTabContentView.css: 96 (.content-view.tab.canvas .navigation-bar > .item .recording > .icon): 97 (.content-view.tab.canvas .navigation-bar > .item > .canvas-overview > .icon): Deleted. 98 Add styles for recording path components. 99 100 * UserInterface/Views/CanvasTabContentView.js: 101 (WI.CanvasTabContentView): 102 (WI.CanvasTabContentView.prototype.treeElementForRepresentedObject): 103 (WI.CanvasTabContentView.prototype.canShowRepresentedObject): 104 (WI.CanvasTabContentView.prototype.showRepresentedObject): 105 (WI.CanvasTabContentView.prototype.shown): 106 (WI.CanvasTabContentView.prototype.restoreStateFromCookie): 107 (WI.CanvasTabContentView.prototype.attached): 108 (WI.CanvasTabContentView.prototype.detached): 109 (WI.CanvasTabContentView.prototype._canvasAdded): 110 (WI.CanvasTabContentView.prototype._canvasRemoved): 111 (WI.CanvasTabContentView.prototype._canvasTreeOutlineSelectionDidChange): 112 (WI.CanvasTabContentView.prototype._recordingStopped): 113 (WI.CanvasTabContentView.prototype._navigationSidebarImport): 114 (WI.CanvasTabContentView.prototype._navigationSidebarTreeOutlineSelectionChanged): 115 (WI.CanvasTabContentView.prototype._recordingAdded): 116 (WI.CanvasTabContentView.prototype._recordingActionIndexChanged): 117 (WI.CanvasTabContentView.prototype._updateActionIndex): 118 (WI.CanvasTabContentView.prototype.restoreFromCookie): Deleted. 119 (WI.CanvasTabContentView.prototype._overviewPathComponentClicked): Deleted. 120 121 * UserInterface/Views/ContentView.js: 122 (WI.ContentView.createFromRepresentedObject): 123 124 * UserInterface/Views/RecordingActionTreeElement.css: 125 (body:not(.window-inactive, .window-docked-inactive) .tree-outline:matches(:focus, .force-focus) .item.action.selected > .titles .parameter.swizzled,): 126 (body:not(.window-inactive, .window-docked-inactive) :matches(:focus, .force-focus) .item.action.selected > .titles .parameter.swizzled,): Deleted. 127 128 * UserInterface/Views/RecordingContentView.css: 129 (.content-view:not(.tab).recording): 130 (.content-view:not(.tab).recording > header): 131 (.content-view:not(.tab).recording > header > .slider-container): 132 (.content-view:not(.tab).recording > header > .slider-container > input[type=range]): 133 (.content-view:not(.tab).recording > header > .slider-container > input[type=range]::-webkit-slider-runnable-track): 134 (.content-view:not(.tab).recording > header > .slider-container > input[type=range]::-webkit-slider-thumb): 135 (.content-view:not(.tab).recording > .preview-container): 136 137 * UserInterface/Views/RecordingContentView.js: 138 (WI.RecordingContentView): 139 (WI.RecordingContentView.prototype.updateActionIndex): 140 (WI.RecordingContentView.prototype.initialLayout): 141 (WI.RecordingContentView.prototype.async._generateContentCanvas2D): 142 (WI.RecordingContentView.prototype._updateSliderValue): 143 (WI.RecordingContentView.prototype._sliderChanged): 144 (WI.RecordingContentView.prototype.get supplementalRepresentedObjects): Deleted. 145 146 * UserInterface/Views/RecordingNavigationSidebarPanel.js: 147 (WI.RecordingNavigationSidebarPanel.prototype.set recording): 148 (WI.RecordingNavigationSidebarPanel.prototype.updateActionIndex): 149 150 * UserInterface/Views/ResourceIcons.css: 151 (.canvas .icon): 152 (.canvas.canvas-2d .icon): Deleted. 153 (.canvas:matches(.webgl, .webgl2, .webgpu) .icon): Deleted. 154 1 155 2017-10-24 Ross Kirsling <ross.kirsling@sony.com> 2 156 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r223806 r223918 32 32 localizedStrings["%d fps"] = "%d fps"; 33 33 localizedStrings["%d matches"] = "%d matches"; 34 localizedStrings["%d of %d"] = "%d of %d"; 34 35 localizedStrings["%dpx"] = "%dpx"; 35 36 localizedStrings["%dpx²"] = "%dpx²"; … … 394 395 localizedStrings["Expires"] = "Expires"; 395 396 localizedStrings["Export"] = "Export"; 397 localizedStrings["Export HAR"] = "Export HAR"; 396 398 localizedStrings["Expression"] = "Expression"; 397 399 localizedStrings["Extension Scripts"] = "Extension Scripts"; … … 987 989 localizedStrings["Vertex Shader"] = "Vertex Shader"; 988 990 localizedStrings["Vertical"] = "Vertical"; 991 localizedStrings["View Recordings... (%d)"] = "View Recordings... (%d)"; 989 992 localizedStrings["View variable value"] = "View variable value"; 990 993 localizedStrings["Visibility"] = "Visibility"; -
trunk/Source/WebInspectorUI/UserInterface/Base/Main.js
r223778 r223918 434 434 WI.NetworkTabContentView, 435 435 WI.NewTabContentView, 436 WI.RecordingTabContentView,437 436 WI.ResourcesTabContentView, 438 437 WI.SearchTabContentView, … … 1103 1102 1104 1103 if (representedObject instanceof WI.Recording) 1105 return WI. RecordingTabContentView;1104 return WI.CanvasTabContentView; 1106 1105 1107 1106 return null; -
trunk/Source/WebInspectorUI/UserInterface/Images/Recording.svg
r220114 r223918 2 2 <!-- Copyright © 2017 Apple Inc. All rights reserved. --> 3 3 <svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16"> 4 <path fill="currentColor" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 M 13 2 C 13.550781 2 14 2.449219 14 3 L 14 13 C 14 13.550781 13.550781 14 13 14 L 3 14 C 2.449219 14 2 13.550781 2 13 L 2 3 C 2 2.449219 2.449219 2 3 2 L 13 2"/> 5 <rect fill="currentColor" x="4.25" y="4.5" width="7.5" height="1"/> 6 <rect fill="currentColor" x="4.25" y="6.5" width="7.5" height="1"/> 7 <rect fill="currentColor" x="4.25" y="8.5" width="7.5" height="1"/> 8 <rect fill="currentColor" x="4.25" y="10.5" width="7.5" height="1"/> 4 <path d="M 6.5 8 A 1.5 1.5 0 1 1 5 6.5 1.5 1.5 0 0 1 6.5 8 Z M 5 9.5 h 6 m 0 -3 A 1.5 1.5 0 1 0 12.5 8 1.5 1.5 0 0 0 11 6.5 Z" fill="none" stroke="currentColor"/> 5 <path d="M1.5 3.729 v 8.542 a 1.127 1.127 0 0 0 1 1.22 h 11 a 1.127 1.127 0 0 0 1 -1.22 V 3.729 a 1.127 1.127 0 0 0 -1 -1.22 H 2.5 A 1.127 1.127 0 0 0 1.5 3.729 Z" fill="none" stroke="currentColor"/> 9 6 </svg> -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r223856 r223918 514 514 <script src="Views/ElementsTabContentView.js"></script> 515 515 <script src="Views/LayersTabContentView.js"></script> 516 <script src="Views/RecordingTabContentView.js"></script>517 516 <script src="Views/ResourceTreeElement.js"></script> 518 517 <script src="Views/ResourcesTabContentView.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js
r223335 r223918 36 36 37 37 this._swizzle = []; 38 this._visualActionIndexes = []; 38 39 this._source = null; 39 40 40 41 let actions = [new WI.RecordingInitialStateAction].concat(...this._frames.map((frame) => frame.actions)); 41 42 this._actions = Promise.all(actions.map((action) => action.swizzle(this))).then(() => { 42 for (let action of actions){43 actions.forEach((action, index) => { 43 44 if (!action.valid) 44 continue;45 return; 45 46 46 47 let prototype = null; … … 59 60 } 60 61 } 61 } 62 63 if (action.isVisual) 64 this._visualActionIndexes.push(index); 65 }); 62 66 63 67 return actions; … … 170 174 get frames() { return this._frames; } 171 175 get data() { return this._data; } 176 get visualActionIndexes() { return this._visualActionIndexes; } 172 177 173 178 get actions() { return this._actions; } -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js
r223011 r223918 42 42 this._pixelSizeElement = null; 43 43 this._canvasNode = null; 44 this._recordingOptionElementMap = new WeakMap; 44 45 45 46 if (this.representedObject.contextType === WI.Canvas.ContextType.Canvas2D || this.representedObject.contextType === WI.Canvas.ContextType.WebGL) { … … 77 78 this.representedObject.requestContent().then((content) => { 78 79 this._pendingContent = content; 80 if (!this._pendingContent) { 81 console.error("Canvas content not available.", this.representedObject); 82 return; 83 } 84 79 85 this.needsLayout(); 80 86 }) … … 103 109 104 110 let navigationBar = new WI.NavigationBar; 105 if (this._recordButtonNavigationItem) {111 if (this._recordButtonNavigationItem) 106 112 navigationBar.addNavigationItem(this._recordButtonNavigationItem); 107 navigationBar.addNavigationItem(new WI.DividerNavigationItem); 108 } 113 109 114 navigationBar.addNavigationItem(this._refreshButtonNavigationItem); 110 115 … … 115 120 116 121 let footer = this.element.appendChild(document.createElement("footer")); 122 123 this._recordingSelectContainer = footer.appendChild(document.createElement("div")); 124 this._recordingSelectContainer.classList.add("recordings", "hidden"); 125 126 this._recordingSelectText = this._recordingSelectContainer.appendChild(document.createElement("span")); 127 128 this._recordingSelectElement = this._recordingSelectContainer.appendChild(document.createElement("select")); 129 this._recordingSelectElement.addEventListener("change", this._handleRecordingSelectElementChange.bind(this)); 130 131 let flexibleSpaceElement = footer.appendChild(document.createElement("div")); 132 flexibleSpaceElement.className = "flexible-space"; 133 117 134 let metrics = footer.appendChild(document.createElement("div")); 118 135 this._pixelSizeElement = metrics.appendChild(document.createElement("span")); … … 180 197 181 198 WI.settings.showImageGrid.addEventListener(WI.Setting.Event.Changed, this._updateImageGrid, this); 199 200 if (this.didInitialLayout) 201 this._recordingSelectElement.selectedIndex = -1; 182 202 } 183 203 … … 230 250 this._updateRecordNavigationItem(); 231 251 232 if (event.data.canvas !== this.representedObject) 233 return; 234 235 if (!event.data.recording) { 236 console.error("Missing recording."); 237 return; 238 } 252 let {canvas, recording} = event.data; 253 if (canvas !== this.representedObject || !recording) 254 return; 255 256 const subtitle = null; 257 let recordingTreeElement = new WI.GeneralTreeElement(["recording"], recording.displayName, subtitle, recording); 258 recordingTreeElement.tooltip = ""; // Tree element tooltips aren't needed in a popover. 259 260 let optionElement = this._recordingSelectElement.appendChild(document.createElement("option")); 261 optionElement.textContent = recording.displayName; 262 263 this._recordingOptionElementMap.set(optionElement, recording); 264 265 let recordingCount = this._recordingSelectElement.options.length; 266 this._recordingSelectText.textContent = WI.UIString("View Recordings... (%d)").format(recordingCount); 267 this._recordingSelectContainer.classList.remove("hidden"); 239 268 240 269 WI.showRepresentedObject(event.data.recording); 270 } 271 272 _handleRecordingSelectElementChange(event) 273 { 274 let selectedOption = this._recordingSelectElement.options[this._recordingSelectElement.selectedIndex]; 275 console.assert(selectedOption, "An option should have been selected."); 276 if (!selectedOption) 277 return; 278 279 let representedObject = this._recordingOptionElementMap.get(selectedOption); 280 console.assert(representedObject, "Missing map entry for option."); 281 if (!representedObject) 282 return; 283 284 WI.showRepresentedObject(representedObject); 241 285 } 242 286 -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.css
r223011 r223918 53 53 54 54 .content-view.canvas-overview .content-view.canvas > header { 55 font-size: 1 4px;55 font-size: 13px; 56 56 } 57 57 … … 75 75 76 76 .content-view.canvas-overview .content-view.canvas > header .subtitle::before { 77 content: " \2014";77 content: " — "; 78 78 } 79 79 … … 95 95 } 96 96 97 .content-view.canvas-overview .content-view.canvas:not(:hover, .is-recording ) > header > .navigation-bar {97 .content-view.canvas-overview .content-view.canvas:not(:hover, .is-recording, .selected) > header > .navigation-bar { 98 98 visibility: hidden; 99 99 } … … 130 130 } 131 131 132 .content-view.canvas-overview .content-view.canvas > footer { 133 /* FIXME: this can be removed once <https://webkit.org/b/177606> is complete.*/ 134 justify-content: flex-end; 132 .content-view.canvas-overview .content-view.canvas > footer > .recordings { 133 position: absolute; 134 display: flex; 135 align-items: center; 136 } 137 138 .content-view.canvas-overview .content-view.canvas > footer > .recordings::before { 139 display: inline-block; 140 width: 16px; 141 margin-top: 3px; 142 -webkit-padding-end: 4px; 143 content: url(../Images/Recording.svg); 144 } 145 146 .content-view.canvas-overview .content-view.canvas > footer > .recordings > select { 147 position: absolute; 148 top: 0; 149 right: 0; 150 bottom: 0; 151 left: 0; 152 margin: 0; 153 padding: 0; 154 border: none; 155 opacity: 0; 156 -webkit-appearance: none; 157 } 158 159 .content-view.canvas-overview .content-view.canvas > footer .recordings > select:focus { 160 -webkit-margin-start: 11px; 161 } 162 163 .content-view.canvas-overview .content-view.canvas > footer > .flexible-space { 164 flex: 1; 135 165 } 136 166 … … 138 168 -webkit-padding-start: 4px; 139 169 } 170 171 .popover-content > .tree-outline .item.recording > .icon { 172 content: url(../Images/Recording.svg); 173 } 174 175 .popover-content > .tree-outline .item.recording:hover { 176 color: var(--selected-foreground-color); 177 background-color: var(--selected-background-color); 178 border-radius: 3px; 179 } 180 181 .popover-content > .tree-outline .item.recording:hover > .icon { 182 filter: invert(); 183 } -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js
r223011 r223918 34 34 this.element.classList.add("canvas-overview"); 35 35 36 this._canvasTreeOutline = new WI.TreeOutline;37 38 36 this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("refresh-all", WI.UIString("Refresh all"), "Images/ReloadFull.svg", 13, 13); 39 37 this._refreshButtonNavigationItem.disabled = true; … … 44 42 this._showGridButtonNavigationItem.disabled = true; 45 43 this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this); 46 47 this._selectedCanvasPathComponent = null;48 44 49 45 this.selectionEnabled = true; … … 60 56 { 61 57 let components = []; 62 let canvas = this.supplementalRepresentedObjects[0]; 63 if (canvas) { 64 let treeElement = this._canvasTreeOutline.findTreeElement(canvas); 65 console.assert(treeElement); 66 if (treeElement) { 67 let pathComponent = new WI.GeneralTreeElementPathComponent(treeElement, canvas); 68 pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._selectedPathComponentChanged, this); 69 components.push(pathComponent); 58 59 if (this.supplementalRepresentedObjects.length) { 60 let [canvas] = this.supplementalRepresentedObjects; 61 let tabContentView = WI.tabBrowser.selectedTabContentView; 62 if (tabContentView) { 63 let treeElement = tabContentView.treeElementForRepresentedObject(canvas); 64 console.assert(treeElement); 65 if (treeElement) { 66 let pathComponent = new WI.GeneralTreeElementPathComponent(treeElement); 67 pathComponent.addEventListener(WI.HierarchicalPathComponent.Event.SiblingWasSelected, this._selectionPathComponentsChanged, this); 68 components.push(pathComponent); 69 } 70 70 } 71 71 } … … 85 85 contentViewAdded(contentView) 86 86 { 87 let canvas = contentView.representedObject;88 let treeElement = this._canvasTreeOutline.findTreeElement(canvas);89 console.assert(!treeElement, "Already added tree element for canvas.", canvas);90 if (treeElement)91 return;92 93 treeElement = new WI.CanvasTreeElement(canvas);94 this._canvasTreeOutline.appendChild(treeElement);95 96 87 contentView.element.addEventListener("mouseenter", this._contentViewMouseEnter); 97 88 contentView.element.addEventListener("mouseleave", this._contentViewMouseLeave); … … 100 91 contentViewRemoved(contentView) 101 92 { 102 let canvas = contentView.representedObject;103 let treeElement = this._canvasTreeOutline.findTreeElement(canvas);104 console.assert(treeElement, "Missing tree element for canvas.", canvas);105 if (!treeElement)106 return;107 108 this._canvasTreeOutline.removeChild(treeElement);109 110 93 contentView.element.removeEventListener("mouseenter", this._contentViewMouseEnter); 111 94 contentView.element.removeEventListener("mouseleave", this._contentViewMouseLeave); … … 138 121 } 139 122 140 _select edPathComponentChanged(event)123 _selectionPathComponentsChanged(event) 141 124 { 142 125 let pathComponent = event.data.pathComponent; … … 152 135 _supplementalRepresentedObjectsDidChange() 153 136 { 154 function createCanvasPathComponent(canvas) {155 return new WI.HierarchicalPathComponent(canvas.displayName, "canvas", canvas);156 }157 158 let currentCanvas = this.supplementalRepresentedObjects[0];159 if (currentCanvas)160 this._selectedCanvasPathComponent = createCanvasPathComponent(currentCanvas);161 else162 this._selectedCanvasPathComponent = null;163 164 137 this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange); 165 138 } -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.css
r223011 r223918 28 28 } 29 29 30 .content-view.tab.canvas .navigation-bar > .item > .canvas-overview > .icon {31 content: url(../Images/CanvasOverview.svg);32 }33 34 30 /* FIXME: this can be removed once <https://webkit.org/b/177606> is complete. */ 35 31 .content-view.tab.canvas .navigation-bar > .item .canvas .icon { 36 32 content: url(../Images/Canvas.svg); 37 33 } 34 35 .content-view.tab.canvas .navigation-bar > .item .recording > .icon { 36 content: url(../Images/Recording.svg); 37 } -
trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js
r223011 r223918 33 33 let tabBarItem = new WI.GeneralTabBarItem(image, title); 34 34 35 const navigationSidebarPanelConstructor = null;35 const navigationSidebarPanelConstructor = WI.RecordingNavigationSidebarPanel; 36 36 const detailsSidebarPanelConstructors = [WI.RecordingStateDetailsSidebarPanel, WI.RecordingTraceDetailsSidebarPanel, WI.CanvasDetailsSidebarPanel]; 37 37 const disableBackForward = true; 38 38 super("canvas", ["canvas"], tabBarItem, navigationSidebarPanelConstructor, detailsSidebarPanelConstructors, disableBackForward); 39 39 40 this._overviewPathComponent = new WI.HierarchicalPathComponent(WI.UIString("Canvas Overview"), "canvas-overview");41 this._overviewPathComponent.addEventListener(WI.HierarchicalPathComponent.Event.Clicked, this._overviewPathComponentClicked, this);42 43 40 this._canvasCollection = null; 44 this._canvasOverviewContentView = null; 41 42 this._canvasTreeOutline = new WI.TreeOutline; 43 this._canvasTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._canvasTreeOutlineSelectionDidChange, this); 44 45 const leftArrow = "Images/BackForwardArrows.svg#left-arrow-mask"; 46 const rightArrow = "Images/BackForwardArrows.svg#right-arrow-mask"; 47 let isRTL = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL; 48 let backButtonImage = isRTL ? rightArrow : leftArrow; 49 this._overviewNavigationItem = new WI.ButtonNavigationItem("canvas-overview", WI.UIString("Canvas Overview"), backButtonImage, 8, 13); 50 this._overviewNavigationItem.hidden = true; 51 this._overviewNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High; 52 this._overviewNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { this.showRepresentedObject(this._canvasCollection); }); 53 54 this.contentBrowser.navigationBar.insertNavigationItem(this._overviewNavigationItem, 2); 55 this.contentBrowser.navigationBar.insertNavigationItem(new WI.DividerNavigationItem, 3); 56 57 this.navigationSidebarPanel.addEventListener(WI.RecordingNavigationSidebarPanel.Event.Import, this._navigationSidebarImport, this); 58 this.navigationSidebarPanel.contentTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._navigationSidebarTreeOutlineSelectionChanged, this); 45 59 } 46 60 … … 61 75 // Public 62 76 77 treeElementForRepresentedObject(representedObject) 78 { 79 return this._canvasTreeOutline.findTreeElement(representedObject); 80 } 81 63 82 get type() 64 83 { … … 73 92 canShowRepresentedObject(representedObject) 74 93 { 75 return representedObject instanceof WI.CanvasCollection; 94 return representedObject instanceof WI.CanvasCollection || representedObject instanceof WI.Recording; 95 } 96 97 showRepresentedObject(representedObject, cookie) 98 { 99 super.showRepresentedObject(representedObject, cookie); 100 101 this.navigationSidebarPanel.recording = null; 102 103 if (representedObject instanceof WI.CanvasCollection) { 104 this._overviewNavigationItem.hidden = true; 105 WI.navigationSidebar.collapsed = true; 106 return; 107 } 108 109 if (representedObject instanceof WI.Recording) { 110 this._overviewNavigationItem.hidden = false; 111 representedObject.actions.then((actions) => { 112 this.navigationSidebarPanel.recording = representedObject; 113 WI.navigationSidebar.collapsed = false; 114 }); 115 return; 116 } 117 118 console.assert(false, "Should not be reached."); 76 119 } 77 120 … … 80 123 super.shown(); 81 124 82 if (this.contentBrowser.currentContentView) 83 return; 84 85 this._canvasOverviewContentView = new WI.CanvasOverviewContentView(this._canvasCollection); 86 this.contentBrowser.showContentView(this._canvasOverviewContentView); 87 } 88 89 treeElementForRepresentedObject(representedObject) 90 { 91 if (!this._overviewTreeElement) { 92 const title = WI.UIString("Canvas Overview"); 93 this._overviewTreeElement = new WI.GeneralTreeElement(["canvas-overview"], title, null, representedObject); 94 } 95 96 return this._overviewTreeElement; 97 } 98 99 restoreFromCookie(cookie) 125 if (!this.contentBrowser.currentContentView) 126 this.showRepresentedObject(this._canvasCollection); 127 } 128 129 restoreStateFromCookie(cookie) 100 130 { 101 131 // FIXME: implement once <https://webkit.org/b/177606> is complete. … … 115 145 WI.canvasManager.addEventListener(WI.CanvasManager.Event.CanvasWasAdded, this._canvasAdded, this); 116 146 WI.canvasManager.addEventListener(WI.CanvasManager.Event.CanvasWasRemoved, this._canvasRemoved, this); 147 WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStopped, this._recordingStopped, this); 117 148 WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this); 149 WI.RecordingContentView.addEventListener(WI.RecordingContentView.Event.RecordingActionIndexChanged, this._recordingActionIndexChanged, this); 118 150 119 151 this._canvasCollection = new WI.CanvasCollection(WI.canvasManager.canvases); 152 153 for (let canvas of this._canvasCollection.items) 154 this._canvasTreeOutline.appendChild(new WI.CanvasTreeElement(canvas)); 120 155 } 121 156 … … 124 159 WI.canvasManager.removeEventListener(null, null, this); 125 160 WI.Frame.removeEventListener(null, null, this); 161 WI.RecordingContentView.removeEventListener(null, null, this); 126 162 127 163 this._canvasCollection = null; 128 164 165 this._canvasTreeOutline.removeChildren(); 166 129 167 super.detached(); 130 168 } … … 135 173 { 136 174 let canvas = event.data.canvas; 175 this._canvasTreeOutline.appendChild(new WI.CanvasTreeElement(canvas)); 137 176 this._canvasCollection.add(canvas); 138 177 } … … 141 180 { 142 181 let canvas = event.data.canvas; 182 let treeElement = this._canvasTreeOutline.findTreeElement(canvas); 183 console.assert(treeElement, "Missing tree element for canvas.", canvas); 184 this._canvasTreeOutline.removeChild(treeElement); 143 185 this._canvasCollection.remove(canvas); 144 186 } 145 187 146 _overviewPathComponentClicked(event) 147 { 148 console.assert(this._canvasOverviewContentView); 149 this.contentBrowser.showContentView(this._canvasOverviewContentView); 188 _canvasTreeOutlineSelectionDidChange(event) 189 { 190 let selectedElement = event.data.selectedElement; 191 if (!selectedElement) 192 return; 193 194 let representedObject = selectedElement.representedObject; 195 196 if (this.canShowRepresentedObject(representedObject)) { 197 this.showRepresentedObject(representedObject); 198 this._updateActionIndex(0); 199 return; 200 } 201 202 if (representedObject instanceof WI.Canvas) { 203 this.showRepresentedObject(this._canvasCollection); 204 this.contentBrowser.currentContentView.setSelectedItem(representedObject); 205 return; 206 } 207 208 console.assert(false, "Unexpected representedObject.", representedObject); 150 209 } 151 210 … … 157 216 this._canvasCollection.clear(); 158 217 } 218 219 _recordingStopped(event) 220 { 221 let recording = event.data.recording; 222 if (!recording) { 223 // FIXME: <https://webkit.org/b/178185> Web Inspector: Canvas tab: show detailed status during canvas recording 224 return; 225 } 226 227 this._recordingAdded(recording); 228 } 229 230 _navigationSidebarImport(event) 231 { 232 let {filename, payload} = event.data; 233 let recording = WI.Recording.fromPayload(payload); 234 if (!recording) { 235 WI.Recording.synthesizeError(WI.UIString("unsupported version.")); 236 return; 237 } 238 239 let extensionStart = filename.lastIndexOf("."); 240 if (extensionStart !== -1) 241 filename = filename.substring(0, extensionStart); 242 243 recording.createDisplayName(filename); 244 245 this._recordingAdded(recording); 246 } 247 248 _navigationSidebarTreeOutlineSelectionChanged(event) 249 { 250 if (!event.data.selectedElement) 251 return; 252 253 let selectedTreeElement = event.data.selectedElement; 254 if (selectedTreeElement instanceof WI.FolderTreeElement) 255 return; 256 257 let recordingContentView = this.contentBrowser.currentContentView; 258 if (!(recordingContentView instanceof WI.RecordingContentView)) 259 return; 260 261 this._updateActionIndex(selectedTreeElement.index, {suppressNavigationSidebarUpdate: true}); 262 } 263 264 _recordingAdded(recording) 265 { 266 const subtitle = null; 267 let recordingTreeElement = new WI.GeneralTreeElement(["recording"], recording.displayName, subtitle, recording); 268 269 if (recording.source) { 270 let canvasTreeElement = this._canvasTreeOutline.findTreeElement(recording.source); 271 console.assert(canvasTreeElement, "Missing tree element for canvas.", recording.source); 272 if (canvasTreeElement) 273 canvasTreeElement.appendChild(recordingTreeElement); 274 } else 275 this._canvasTreeOutline.appendChild(recordingTreeElement); 276 277 this.showRepresentedObject(recording); 278 this._updateActionIndex(0, {suppressNavigationSidebarUpdate: true}); 279 } 280 281 _recordingActionIndexChanged(event) 282 { 283 if (event.target !== this.contentBrowser.currentContentView) 284 return; 285 286 this._updateActionIndex(event.data.index); 287 } 288 289 _updateActionIndex(index, options = {}) 290 { 291 options.actionCompletedCallback = (action, context) => { 292 for (let detailsSidebarPanel of this.detailsSidebarPanels) { 293 if (detailsSidebarPanel.updateAction) 294 detailsSidebarPanel.updateAction(action, context, options); 295 } 296 }; 297 298 if (!options.suppressNavigationSidebarUpdate) 299 this.navigationSidebarPanel.updateActionIndex(index, options); 300 301 this.contentBrowser.currentContentView.updateActionIndex(index, options); 302 } 159 303 }; 160 304 -
trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js
r222599 r223918 61 61 return new WI.CanvasContentView(representedObject, extraArguments); 62 62 63 if (representedObject instanceof WI.CanvasCollection) 64 return new WI.CanvasOverviewContentView(representedObject, extraArguments); 65 63 66 if (representedObject instanceof WI.ShaderProgram) 64 67 return new WI.ShaderProgramContentView(representedObject, extraArguments); -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingActionTreeElement.css
r223694 r223918 66 66 } 67 67 68 body:not(.window-inactive, .window-docked-inactive) :matches(:focus, .force-focus) .item.action.selected > .titles .parameter.swizzled,69 body:not(.window-inactive, .window-docked-inactive) :matches(:focus, .force-focus) .item.action.selected::before {70 color: var(-- console-secondary-text-color);68 body:not(.window-inactive, .window-docked-inactive) .tree-outline:matches(:focus, .force-focus) .item.action.selected > .titles .parameter.swizzled, 69 body:not(.window-inactive, .window-docked-inactive) .tree-outline:matches(:focus, .force-focus) .item.action.selected::before { 70 color: var(--selected-secondary-text-color); 71 71 } 72 72 -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.css
r221232 r223918 25 25 26 26 .content-view:not(.tab).recording { 27 padding: 15px; 27 display: flex; 28 flex-direction: column; 29 padding: 10px; 28 30 background-color: hsl(0, 0%, 90%); 31 } 32 33 .content-view:not(.tab).recording > header { 34 margin-bottom: 10px; 35 } 36 37 .content-view:not(.tab).recording > header > .slider-container { 38 display: flex; 39 padding: 8px; 40 background-color: white; 41 border: 1px solid var(--border-color); 42 border-radius: 4px; 43 } 44 45 .content-view:not(.tab).recording > header > .slider-container > input[type=range] { 46 flex: 1; 47 -webkit-margin-start: 10px; 48 } 49 50 .content-view:not(.tab).recording > header > .slider-container > input[type=range]::-webkit-slider-runnable-track { 51 height: 2px; 52 background-color: var(--border-color); 53 border-radius: 1px; 54 } 55 56 .content-view:not(.tab).recording > header > .slider-container > input[type=range]::-webkit-slider-thumb { 57 margin-top: -6px; 29 58 } 30 59 31 60 .content-view:not(.tab).recording > .preview-container { 32 61 display: flex; 62 flex: 1; 63 justify-content: center; 33 64 align-items: center; 34 justify-content: center;35 65 position: relative; 36 66 width: 100%; -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js
r223335 r223918 54 54 this._showGridButtonNavigationItem.activated = !!WI.settings.showImageGrid.value; 55 55 } 56 57 this._previewContainer = this.element.appendChild(document.createElement("div"));58 this._previewContainer.classList.add("preview-container");59 60 this._messageElement = this.element.appendChild(document.createElement("div"));61 this._messageElement.classList.add("message");62 56 } 63 57 … … 108 102 return; 109 103 104 if (this._index === index) 105 return; 106 110 107 this.representedObject.actions.then((actions) => { 111 108 console.assert(index >= 0 && index < actions.length); 112 if (index < 0 || index >= actions.length || index === this._index)109 if (index < 0 || index >= actions.length) 113 110 return; 114 111 115 112 this._index = index; 113 this._updateSliderValue(); 116 114 117 115 if (this.representedObject.type === WI.Recording.Type.Canvas2D) … … 137 135 } 138 136 139 get supplementalRepresentedObjects()140 {141 let supplementalRepresentedObjects = super.supplementalRepresentedObjects;142 if (this.representedObject)143 supplementalRepresentedObjects.push(this.representedObject);144 return supplementalRepresentedObjects;145 }146 137 147 138 get supportsSave() … … 161 152 forceSaveAs: true, 162 153 }; 154 } 155 156 // Protected 157 158 initialLayout() 159 { 160 let previewHeader = this.element.appendChild(document.createElement("header")); 161 162 let sliderContainer = previewHeader.appendChild(document.createElement("div")); 163 sliderContainer.className = "slider-container hidden"; 164 165 this._previewContainer = this.element.appendChild(document.createElement("div")); 166 this._previewContainer.className = "preview-container"; 167 168 this._sliderValueElement = sliderContainer.appendChild(document.createElement("div")); 169 this._sliderValueElement.className = "slider-value"; 170 171 this._sliderElement = sliderContainer.appendChild(document.createElement("input")); 172 this._sliderElement.addEventListener("input", this._sliderChanged.bind(this)); 173 this._sliderElement.type = "range"; 174 this._sliderElement.min = 0; 175 this._sliderElement.max = 0; 176 177 this.representedObject.actions.then(() => { 178 sliderContainer.classList.remove("hidden"); 179 this._sliderElement.max = this.representedObject.visualActionIndexes.length; 180 this._updateSliderValue(); 181 }); 163 182 } 164 183 … … 397 416 398 417 this._previewContainer.removeChildren(); 399 this._messageElement.removeChildren();400 418 401 419 if (showCanvasPath) { … … 482 500 } 483 501 502 _updateSliderValue() 503 { 504 if (!this._sliderElement) 505 return; 506 507 let visualActionIndexes = this.representedObject.visualActionIndexes; 508 let visualActionIndex = 0; 509 if (this._index > 0) { 510 while (visualActionIndex < visualActionIndexes.length && visualActionIndexes[visualActionIndex] <= this._index) 511 visualActionIndex++; 512 } 513 514 this._sliderElement.value = visualActionIndex; 515 this._sliderValueElement.textContent = WI.UIString("%d of %d").format(visualActionIndex, visualActionIndexes.length); 516 } 517 484 518 _showPathButtonClicked(event) 485 519 { … … 495 529 this._updateImageGrid(); 496 530 } 531 532 _sliderChanged() 533 { 534 let index = 0; 535 536 let visualActionIndex = parseInt(this._sliderElement.value) - 1; 537 if (visualActionIndex !== -1) 538 index = this.representedObject.visualActionIndexes[visualActionIndex]; 539 540 this.dispatchEventToListeners(WI.RecordingContentView.Event.RecordingActionIndexChanged, {index}); 541 } 497 542 }; 498 543 499 544 WI.RecordingContentView.SnapshotInterval = 5000; 545 546 WI.RecordingContentView.Event = { 547 RecordingActionIndexChanged: "recording-action-index-changed", 548 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingNavigationSidebarPanel.js
r223322 r223918 89 89 90 90 this._exportButton.disabled = !actions.length; 91 92 let index = this._recording[WI.RecordingNavigationSidebarPanel.SelectedActionIndexSymbol] || 0; 93 this.updateActionIndex(index); 91 94 }); 92 95 } … … 98 101 99 102 this._recording.actions.then((actions) => { 100 console.assert(index >= 0 && index < actions.length); 101 if (index < 0 || index >= actions.length) 102 return; 103 104 let treeOutline = this.contentTreeOutline; 105 if (!(actions[0] instanceof WI.RecordingInitialStateAction) || index) { 106 treeOutline = treeOutline.children[0]; 107 while (index > treeOutline.children.length) { 108 index -= treeOutline.children.length; 109 treeOutline = treeOutline.nextSibling; 110 } 111 112 // Must subtract one from the final result since the initial state is considered index 0. 113 --index; 114 } 115 116 let treeElementToSelect = treeOutline.children[index]; 117 if (treeElementToSelect.parent && !treeElementToSelect.parent.expanded) 118 treeElementToSelect = treeElementToSelect.parent; 103 let recordingAction = actions[index]; 104 console.assert(recordingAction, "Invalid recording action index.", index); 105 if (!recordingAction) 106 return; 107 108 let treeElement = this.contentTreeOutline.findTreeElement(recordingAction); 109 console.assert(treeElement, "Missing tree element for recording action.", recordingAction); 110 if (!treeElement) 111 return; 112 113 this._recording[WI.RecordingNavigationSidebarPanel.SelectedActionIndexSymbol] = index; 119 114 120 115 const omitFocus = false; 121 116 const selectedByUser = false; 122 let suppressOnSelect = !(treeElementToSelect instanceof WI.FolderTreeElement);117 const suppressOnSelect = true; 123 118 const suppressOnDeselect = true; 124 treeElement ToSelect.revealAndSelect(omitFocus, selectedByUser, suppressOnSelect, suppressOnDeselect);119 treeElement.revealAndSelect(omitFocus, selectedByUser, suppressOnSelect, suppressOnDeselect); 125 120 }); 126 121 } … … 204 199 }; 205 200 201 WI.RecordingNavigationSidebarPanel.SelectedActionIndexSymbol = Symbol("selected-action-index"); 202 206 203 WI.RecordingNavigationSidebarPanel.Event = { 207 204 Import: "recording-navigation-sidebar-panel-import", -
trunk/Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css
r222739 r223918 77 77 } 78 78 79 .canvas.canvas-2d .icon { 80 content: url(../Images/Canvas2D.svg); 81 } 82 83 .canvas:matches(.webgl, .webgl2, .webgpu) .icon { 84 content: url(../Images/Canvas3D.svg); 79 .canvas .icon { 80 content: url(../Images/Canvas.svg); 85 81 } 86 82
Note: See TracChangeset
for help on using the changeset viewer.