Changeset 162560 in webkit
- Timestamp:
- Jan 22, 2014, 2:57:11 PM (11 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r162528 r162560 1 2014-01-22 Timothy Hatcher <timothy@apple.com> 2 3 Support collapsing call site records into the resource timeline. 4 5 Also fix some filtering and graph issues. 6 7 https://bugs.webkit.org/show_bug.cgi?id=127440 8 9 Reviewed by Joseph Pecoraro. 10 11 * UserInterface/NavigationSidebarPanel.js: 12 (WebInspector.NavigationSidebarPanel.prototype.updateFilter): 13 (WebInspector.NavigationSidebarPanel.prototype.applyFiltersToTreeElement.matchTextFilter): 14 (WebInspector.NavigationSidebarPanel.prototype.applyFiltersToTreeElement.makeVisible): 15 (WebInspector.NavigationSidebarPanel.prototype.applyFiltersToTreeElement): 16 (WebInspector.NavigationSidebarPanel.prototype._updateFilter): 17 Tweak how filtering happens so custom filters never expand to reveal and auto expanded 18 tree elements will auto-collapse again later even with custom filters. 19 20 * UserInterface/OverviewTimelineView.css: 21 (.timeline-view.overview > .data-grid tr.parent:not(.expanded) td.graph-column .timeline-record-bar:not(.timeline-record-type-network) > .segment): 22 (.timeline-view.overview > .data-grid tr.parent:not(.expanded).selected td.graph-column .timeline-record-bar:not(.timeline-record-type-network) > .segment): 23 (.timeline-view.overview > .data-grid:focus tr.parent:not(.expanded).selected td.graph-column .timeline-record-bar:not(.timeline-record-type-network) > .segment): 24 Add a shadow to provide some negative space between juxtaposed records. Only needed when not expanded. 25 26 * UserInterface/OverviewTimelineView.js: 27 (WebInspector.OverviewTimelineView.prototype.updateLayout): 28 (WebInspector.OverviewTimelineView.prototype._addResourceToTreeIfNeeded): 29 Update the filter when current time changes and only auto expand the main resource. 30 31 * UserInterface/ResourceTimelineDataGridNode.js: 32 (WebInspector.ResourceTimelineDataGridNode): 33 (WebInspector.ResourceTimelineDataGridNode.prototype._timelineRecordUpdated): 34 Don't schedule a refresh of the graph if the record isn't visible. 35 36 * UserInterface/SourceCodeTimelineTimelineDataGridNode.js: 37 (WebInspector.SourceCodeTimelineTimelineDataGridNode): 38 (WebInspector.SourceCodeTimelineTimelineDataGridNode.prototype._timelineRecordAdded): 39 Don't schedule a refresh of the graph if the record isn't visible. 40 41 * UserInterface/TimelineContentView.js: 42 (WebInspector.TimelineContentView.prototype._timeRangeSelectionChanged): 43 Remove the boolean for updateFilter. 44 45 * UserInterface/TimelineDataGrid.js: 46 (WebInspector.TimelineDataGrid.prototype._refreshDirtyDataGridNodes): 47 (WebInspector.TimelineDataGrid.prototype._sort): 48 Keep the hidden state in-sync between node and element. 49 50 * UserInterface/TimelineDataGridNode.js: 51 (WebInspector.TimelineDataGridNode.prototype.collapse): 52 (WebInspector.TimelineDataGridNode.prototype.expand): 53 (WebInspector.TimelineDataGridNode.prototype.appendChild): 54 (WebInspector.TimelineDataGridNode.prototype.insertChild): 55 (WebInspector.TimelineDataGridNode.prototype.removeChild): 56 (WebInspector.TimelineDataGridNode.prototype.removeChildren): 57 (WebInspector.TimelineDataGridNode.prototype.removeChildrenRecursive): 58 (WebInspector.TimelineDataGridNode.prototype.refreshGraph.createBarsForRecords): 59 (WebInspector.TimelineDataGridNode.prototype.refreshGraph.else.collectRecordsByType.get if): 60 (WebInspector.TimelineDataGridNode.prototype.needsGraphRefresh): 61 (WebInspector.TimelineDataGridNode.prototype.isRecordVisible): 62 Support drawing the children records on the parent graph. 63 64 * UserInterface/TimelineRecordBar.css: 65 (.timeline-record-bar.unfinished > .segment): 66 (:focus .selected .timeline-record-bar > .segment): 67 (:focus .selected .timeline-record-bar > .segment.inactive): 68 (:focus .selected .timeline-record-bar.has-inactive-segment > .segment:not(.inactive)): 69 Tweaked styles to look better when selected. 70 71 * UserInterface/TimelineRecordBar.js: 72 (WebInspector.TimelineRecordBar.recordsCannotBeCombined): 73 (WebInspector.TimelineRecordBar.prototype.set records): 74 (WebInspector.TimelineRecordBar.prototype.refresh): 75 Drive-by fixes for some bug with bars being reused. 76 1 77 2014-01-21 Timothy Hatcher <timothy@apple.com> 2 78 -
trunk/Source/WebInspectorUI/UserInterface/NavigationSidebarPanel.js
r162414 r162560 293 293 }, 294 294 295 updateFilter: function( dontExpandOnMatch)296 { 297 this._updateFilter( dontExpandOnMatch);295 updateFilter: function() 296 { 297 this._updateFilter(); 298 298 }, 299 299 … … 310 310 }, 311 311 312 applyFiltersToTreeElement: function(treeElement , dontExpandOnMatch)312 applyFiltersToTreeElement: function(treeElement) 313 313 { 314 314 if (!this._filterBar.hasActiveFilters() && !this.hasCustomFilters()) { … … 326 326 327 327 var filterableData = treeElement.filterableData || {}; 328 329 var matchedBuiltInFilters = false; 328 330 329 331 var self = this; … … 341 343 if (!input) 342 344 continue; 343 if (self._textFilterRegex.test(input)) 345 if (self._textFilterRegex.test(input)) { 346 matchedBuiltInFilters = true; 344 347 return true; 348 } 345 349 } 346 350 … … 359 363 currentAncestor.hidden = false; 360 364 361 if (!currentAncestor.expanded && !dontExpandOnMatch) { 365 // Only expand if the built-in filters matched, not custom filters. 366 if (matchedBuiltInFilters && !currentAncestor.expanded) { 362 367 currentAncestor.__wasExpandedDuringFiltering = true; 363 368 currentAncestor.expand(); … … 371 376 // Make this element visible since it matches. 372 377 makeVisible(); 378 379 // If this tree element didn't match a built-in filter and was expanded earlier during filtering, collapse it again. 380 if (!matchedBuiltInFilters && treeElement.expanded && treeElement.__wasExpandedDuringFiltering) { 381 delete treeElement.__wasExpandedDuringFiltering; 382 treeElement.collapse(); 383 } 384 373 385 return; 374 386 } … … 469 481 }, 470 482 471 _updateFilter: function( dontExpandOnMatch)483 _updateFilter: function() 472 484 { 473 485 var filters = this._filterBar.filters; … … 478 490 var currentTreeElement = this._contentTreeOutline.children[0]; 479 491 while (currentTreeElement && !currentTreeElement.root) { 480 this.applyFiltersToTreeElement(currentTreeElement , dontExpandOnMatch);492 this.applyFiltersToTreeElement(currentTreeElement); 481 493 currentTreeElement = currentTreeElement.traverseNextTreeElement(false, null, false); 482 494 } -
trunk/Source/WebInspectorUI/UserInterface/OverviewTimelineView.css
r162412 r162560 70 70 top: 2px; 71 71 } 72 73 .timeline-view.overview > .data-grid tr.parent:not(.expanded) td.graph-column .timeline-record-bar:not(.has-inactive-segment) > .segment { 74 box-shadow: white 0 0 0 1px; 75 } 76 77 .timeline-view.overview > .data-grid tr.parent:not(.expanded).selected td.graph-column .timeline-record-bar:not(.has-inactive-segment) > .segment { 78 box-shadow: rgb(212, 212, 212) 0 0 0 1px; 79 } 80 81 .timeline-view.overview > .data-grid:focus tr.parent:not(.expanded).selected td.graph-column .timeline-record-bar:not(.has-inactive-segment) > .segment { 82 box-shadow: rgb(56, 121, 217) 0 0 0 1px; 83 } 84 85 .timeline-view.overview > .data-grid tr.parent:not(.expanded) td.graph-column .timeline-record-bar.has-inactive-segment > .segment:not(.inactive) { 86 box-shadow: white 1px 0 0; 87 } 88 89 .timeline-view.overview > .data-grid tr.parent:not(.expanded).selected td.graph-column .timeline-record-bar.has-inactive-segment > .segment:not(.inactive) { 90 box-shadow: rgb(212, 212, 212) 1px 0 0; 91 } 92 93 .timeline-view.overview > .data-grid:focus tr.parent:not(.expanded).selected td.graph-column .timeline-record-bar.has-inactive-segment > .segment:not(.inactive) { 94 box-shadow: rgb(56, 121, 217) 1px 0 0; 95 } -
trunk/Source/WebInspectorUI/UserInterface/OverviewTimelineView.js
r162527 r162560 94 94 // We only need to refresh the graphs when the any of the times change. 95 95 if (this.zeroTime !== oldZeroTime || this.startTime !== oldStartTime || this.endTime !== oldEndTime || this.currentTime !== oldCurrentTime) { 96 var item= this._dataGrid.children[0];97 while ( item) {98 item.refreshGraph();99 item = item.traverseNextNode(false, null, true);96 var dataGridNode = this._dataGrid.children[0]; 97 while (dataGridNode) { 98 dataGridNode.refreshGraph(); 99 dataGridNode = dataGridNode.traverseNextNode(true, null, true); 100 100 } 101 } 102 103 if (!this.currentTime !== oldCurrentTime) { 104 // Check the filters again since the current time change might have revealed this node. Start and end time changes are handled by TimelineContentView. 105 WebInspector.timelineSidebarPanel.updateFilter(); 101 106 } 102 107 … … 217 222 return; 218 223 219 if (parentFrame.mainResource === resource || parentFrame.provisionalMainResource === resource) 224 var expandedByDefault = false; 225 if (parentFrame.mainResource === resource || parentFrame.provisionalMainResource === resource) { 220 226 parentFrame = parentFrame.parentFrame; 227 expandedByDefault = !parentFrame; // Main frame expands by default. 228 } 221 229 222 230 var resourceTreeElement = new WebInspector.ResourceTreeElement(resource); 223 resourceTreeElement.expand(); 231 if (expandedByDefault) 232 resourceTreeElement.expand(); 224 233 225 234 var resourceTimelineRecord = this._networkTimeline ? this._networkTimeline.recordForResource(resource) : null; -
trunk/Source/WebInspectorUI/UserInterface/ResourceTimelineDataGridNode.js
r162415 r162560 31 31 this._record = resourceTimelineRecord; 32 32 33 this._record.addEventListener(WebInspector.TimelineRecord.Event.Updated, graphOnly ? this. needsGraphRefresh: this._needsRefresh, this);33 this._record.addEventListener(WebInspector.TimelineRecord.Event.Updated, graphOnly ? this._timelineRecordUpdated : this._needsRefresh, this); 34 34 35 35 if (!graphOnly) { … … 183 183 { 184 184 WebInspector.resourceSidebarPanel.showSourceCode(this._resource); 185 }, 186 187 _timelineRecordUpdated: function(event) 188 { 189 if (this.isRecordVisible(this._record)) 190 this.needsGraphRefresh(); 185 191 } 186 192 }; -
trunk/Source/WebInspectorUI/UserInterface/SourceCodeTimelineTimelineDataGridNode.js
r162412 r162560 29 29 30 30 this._sourceCodeTimeline = sourceCodeTimeline; 31 this._sourceCodeTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this. needsGraphRefresh, this);31 this._sourceCodeTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._timelineRecordAdded, this); 32 32 }; 33 33 … … 53 53 { 54 54 return {graph: this._sourceCodeTimeline.startTime}; 55 }, 56 57 // Private 58 59 _timelineRecordAdded: function(event) 60 { 61 if (this.isRecordVisible(event.data.record)) 62 this.needsGraphRefresh(); 55 63 } 56 64 }; -
trunk/Source/WebInspectorUI/UserInterface/TimelineContentView.js
r162527 r162560 405 405 406 406 // Delay until the next frame to stay in sync with the current timeline view's time-based layout changes. 407 requestAnimationFrame(function() { WebInspector.timelineSidebarPanel.updateFilter( true); });407 requestAnimationFrame(function() { WebInspector.timelineSidebarPanel.updateFilter(); }); 408 408 } 409 409 }; -
trunk/Source/WebInspectorUI/UserInterface/TimelineDataGrid.js
r162527 r162560 239 239 this.insertChild(dataGridNode, insertionIndex); 240 240 241 // Adding the tree element back to the tree outline subjects it to filters. 242 // Make sure we keep the hidden state in-sync while the synchronizer is disabled. 243 dataGridNode.element.classList.toggle("hidden", treeElement.hidden); 244 241 245 if (dataGridNode === selectedNode) { 242 246 selectedNode.revealAndSelect(); … … 275 279 treeOutline.appendChild(treeElement); 276 280 this.appendChild(dataGridNode); 281 282 // Adding the tree element back to the tree outline subjects it to filters. 283 // Make sure we keep the hidden state in-sync while the synchronizer is disabled. 284 dataGridNode.element.classList.toggle("hidden", treeElement.hidden); 277 285 } 278 286 -
trunk/Source/WebInspectorUI/UserInterface/TimelineDataGridNode.js
r162419 r162560 65 65 }, 66 66 67 collapse: function() 68 { 69 WebInspector.DataGridNode.prototype.collapse.call(this); 70 71 // Refresh to show child bars in our graph now that we collapsed. 72 this.refreshGraph(); 73 }, 74 75 expand: function() 76 { 77 WebInspector.DataGridNode.prototype.expand.call(this); 78 79 if (!this.revealed) 80 return; 81 82 // Refresh to remove child bars from our graph now that we expanded. 83 this.refreshGraph(); 84 85 // Refresh child graphs since they haven't been updating while we were collapsed. 86 var childNode = this.children[0]; 87 while (childNode) { 88 if (childNode instanceof WebInspector.TimelineDataGridNode) 89 childNode.refreshGraph(); 90 childNode = childNode.traverseNextNode(true, this); 91 } 92 }, 93 67 94 createCellContent: function(columnIdentifier, cell) 68 95 { … … 199 226 } 200 227 201 var records = this.records; 202 if (!records || !records.length) 203 return; 204 205 // Fast path for single records. 206 if (records.length === 1) { 207 var record = records[0]; 208 var timelineRecordBar = this._timelineRecordBars[0]; 209 210 if (timelineRecordBar && timelineRecordBar.record !== record) { 211 timelineRecordBar.element.remove(); 212 timelineRecordBar = null; 213 } 214 215 if (!timelineRecordBar) 216 timelineRecordBar = this._timelineRecordBars[0] = new WebInspector.TimelineRecordBar(record); 217 218 if (timelineRecordBar.refresh(this._graphDataSource)) { 219 if (!timelineRecordBar.element.parentNode) 220 this._graphContainerElement.appendChild(timelineRecordBar.element); 221 } else 222 timelineRecordBar.element.remove(); 223 224 return; 225 } 226 227 // Multiple records attempt to share a bar if their time is close to prevent overlapping bars. 228 if (!this.revealed) { 229 // We are not visible, but an ancestor will be drawing our graph. 230 // Notify the next visible ancestor to refresh their graph. 231 var ancestor = this; 232 while (ancestor && !ancestor.root) { 233 if (ancestor.revealed && ancestor instanceof WebInspector.TimelineDataGridNode) { 234 ancestor.refreshGraph(); 235 return; 236 } 237 238 ancestor = ancestor.parent; 239 } 240 241 return; 242 } 243 228 244 var startTime = this._graphDataSource.startTime; 229 245 var currentTime = this._graphDataSource.currentTime; … … 232 248 var visibleWidth = this._graphContainerElement.offsetWidth; 233 249 var secondsPerPixel = duration / visibleWidth; 234 235 250 var recordBarIndex = 0; 236 var barRecords = [];237 251 238 252 function createBar(barRecords) … … 248 262 } 249 263 250 for (var record of records) { 251 // Combining multiple record bars is not supported with records that have inactive time. 252 // ResourceTimelineRecord is the only one right, and it is always a single record handled above. 253 console.assert(!record.usesActiveStartTime); 254 255 if (isNaN(record.startTime)) 256 continue; 257 258 // If this bar is completely before the bounds of the graph, skip this record. 259 if (record.endTime < startTime) 260 continue; 261 262 // If this record is completely after the current time or end time, break out now. 263 // Records are sorted, so all records after this will be beyond the current or end time too. 264 if (record.startTime > currentTime || record.startTime > endTime) 265 break; 266 267 // Check if the previous record can be combined with the current record, if not make a new bar. 268 if (barRecords.length && WebInspector.TimelineRecordBar.recordsCannotBeCombined(barRecords, record, secondsPerPixel)) { 264 function createBarsForRecords(records) 265 { 266 var barRecords = []; 267 268 for (var record of records) { 269 if (isNaN(record.startTime)) 270 continue; 271 272 // If this bar is completely before the bounds of the graph, skip this record. 273 if (record.endTime < startTime) 274 continue; 275 276 // If this record is completely after the current time or end time, break out now. 277 // Records are sorted, so all records after this will be beyond the current or end time too. 278 if (record.startTime > currentTime || record.startTime > endTime) 279 break; 280 281 // Check if the previous record can be combined with the current record, if not make a new bar. 282 if (barRecords.length && WebInspector.TimelineRecordBar.recordsCannotBeCombined(barRecords, record, secondsPerPixel)) { 283 createBar.call(this, barRecords); 284 barRecords = []; 285 } 286 287 barRecords.push(record); 288 } 289 290 // Create the bar for the last record if needed. 291 if (barRecords.length) 269 292 createBar.call(this, barRecords); 270 barRecords = []; 271 } 272 273 barRecords.push(record); 274 } 275 276 // Create the bar for the last record if needed. 277 if (barRecords.length) 278 createBar.call(this, barRecords); 293 } 294 295 if (this.expanded) { 296 // When expanded just use the records for this node. 297 createBarsForRecords.call(this, this.records); 298 } else { 299 // When collapsed use the records for this node and its descendants. 300 // To share bars better, group records by type. 301 302 var recordTypeMap = new Map; 303 304 function collectRecordsByType(records) 305 { 306 for (var record of records) { 307 var typedRecords = recordTypeMap.get(record.type); 308 if (!typedRecords) { 309 typedRecords = []; 310 recordTypeMap.set(record.type, typedRecords); 311 } 312 313 typedRecords.push(record); 314 } 315 } 316 317 collectRecordsByType(this.records); 318 319 var childNode = this.children[0]; 320 while (childNode) { 321 if (childNode instanceof WebInspector.TimelineDataGridNode) 322 collectRecordsByType(childNode.records); 323 childNode = childNode.traverseNextNode(false, this); 324 } 325 326 for (var records of recordTypeMap.values()) 327 createBarsForRecords.call(this, records); 328 } 279 329 280 330 // Remove the remaining unused TimelineRecordBars. … … 291 341 292 342 this._scheduledGraphRefreshIdentifier = requestAnimationFrame(this.refreshGraph.bind(this)); 343 }, 344 345 // Protected 346 347 isRecordVisible: function(record) 348 { 349 if (!this._graphDataSource) 350 return false; 351 352 if (isNaN(record.startTime)) 353 return false; 354 355 // If this bar is completely before the bounds of the graph, not visible. 356 if (record.endTime < this.graphDataSource.startTime) 357 return false; 358 359 // If this record is completely after the current time or end time, not visible. 360 if (record.startTime > this.graphDataSource.currentTime || record.startTime > this.graphDataSource.endTime) 361 return false; 362 363 return true; 293 364 } 294 365 }; -
trunk/Source/WebInspectorUI/UserInterface/TimelineRecordBar.css
r162419 r162560 36 36 border-radius: 3px; 37 37 min-width: 4px; 38 z-index: 1; 38 39 } 39 40 … … 43 44 } 44 45 46 .timeline-record-bar > .segment.inactive { 47 z-index: 0; 48 } 49 45 50 .timeline-record-bar > .segment.inactive, 46 51 .timeline-record-bar.unfinished > .segment { … … 48 53 border-bottom-right-radius: 0 !important; 49 54 border-right: none; 55 margin-right: -1px; 50 56 } 51 57 … … 57 63 :focus .selected .timeline-record-bar > .segment { 58 64 background-color: white !important; 59 border-color: white !important; 65 border: none !important; 66 } 67 68 :focus .selected .timeline-record-bar > .segment.inactive { 69 opacity: 0.7; 70 } 71 72 :focus .selected .timeline-record-bar.has-inactive-segment > .segment:not(.inactive) { 73 border-left: 1px solid rgba(56, 121, 217, 0.7) !important; 60 74 } 61 75 -
trunk/Source/WebInspectorUI/UserInterface/TimelineRecordBar.js
r162419 r162560 59 59 return true; 60 60 61 if (candidateRecord.usesActiveStartTime) 62 return true; 63 61 64 var lastRecord = records.lastValue; 65 if (lastRecord.usesActiveStartTime) 66 return true; 67 62 68 if (lastRecord.type !== candidateRecord.type) 63 69 return true; … … 113 119 this._inactiveBarElement.classList.add(WebInspector.TimelineRecordBar.InactiveStyleClassName); 114 120 this._element.classList.add(WebInspector.TimelineRecordBar.HasInactiveSegmentStyleClassName); 115 this._element.insertBefore(this._inactiveBarElement, this._ activeBarElement);121 this._element.insertBefore(this._inactiveBarElement, this._element.firstChild); 116 122 } 117 123 } else if (this._inactiveBarElement) { 124 this._element.classList.remove(WebInspector.TimelineRecordBar.HasInactiveSegmentStyleClassName); 118 125 this._inactiveBarElement.remove(); 119 126 delete this._inactiveBarElement; … … 166 173 this._updateElementPosition(this._element, newBarWidth, "width"); 167 174 168 if (!this._inactiveBarElement) 175 if (!this._inactiveBarElement) { 176 // If this TimelineRecordBar is reused and had an inactive bar previously, 177 // we might need to remove some styles and add the active element back. 178 this._activeBarElement.style.removeProperty("left"); 179 this._activeBarElement.style.removeProperty("width"); 180 if (!this._activeBarElement.parentNode) 181 this._element.appendChild(this._activeBarElement); 169 182 return true; 183 } 170 184 171 185 console.assert(firstRecord === lastRecord);
Note:
See TracChangeset
for help on using the changeset viewer.