diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineOverviewGraph.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineOverviewGraph.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineOverviewGraph.js | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineOverviewGraph.js b/Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineOverviewGraph.js new file mode 100644 index 000000000..5a74257d0 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineOverviewGraph.js @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.RenderingFrameTimelineOverviewGraph = class RenderingFrameTimelineOverviewGraph extends WebInspector.TimelineOverviewGraph +{ + constructor(timeline, timelineOverview) + { + super(timelineOverview); + + this.element.classList.add("rendering-frame"); + this.element.addEventListener("click", this._mouseClicked.bind(this)); + + this._renderingFrameTimeline = timeline; + this._renderingFrameTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._timelineRecordAdded, this); + + this._selectedFrameMarker = document.createElement("div"); + this._selectedFrameMarker.classList.add("frame-marker"); + + this._timelineRecordFrames = []; + this._selectedTimelineRecordFrame = null; + this._graphHeightSeconds = NaN; + this._framesPerSecondDividerMap = new Map; + + this.reset(); + } + + // Public + + get graphHeightSeconds() + { + if (!isNaN(this._graphHeightSeconds)) + return this._graphHeightSeconds; + + var maximumFrameDuration = this._renderingFrameTimeline.records.reduce(function(previousValue, currentValue) { + return Math.max(previousValue, currentValue.duration); + }, 0); + + this._graphHeightSeconds = maximumFrameDuration * 1.1; // Add 10% margin above frames. + this._graphHeightSeconds = Math.min(this._graphHeightSeconds, WebInspector.RenderingFrameTimelineOverviewGraph.MaximumGraphHeightSeconds); + this._graphHeightSeconds = Math.max(this._graphHeightSeconds, WebInspector.RenderingFrameTimelineOverviewGraph.MinimumGraphHeightSeconds); + return this._graphHeightSeconds; + } + + reset() + { + super.reset(); + + this.element.removeChildren(); + + this.selectedRecord = null; + + this._framesPerSecondDividerMap.clear(); + } + + recordWasFiltered(record, filtered) + { + super.recordWasFiltered(record, filtered); + + if (!(record instanceof WebInspector.RenderingFrameTimelineRecord)) + return; + + record[WebInspector.RenderingFrameTimelineOverviewGraph.RecordWasFilteredSymbol] = filtered; + + // Set filtered style if the frame element is within the visible range. + const startIndex = Math.floor(this.startTime); + const endIndex = Math.min(Math.floor(this.endTime), this._renderingFrameTimeline.records.length - 1); + if (record.frameIndex < startIndex || record.frameIndex > endIndex) + return; + + const frameIndex = record.frameIndex - startIndex; + this._timelineRecordFrames[frameIndex].filtered = filtered; + } + + // Protected + + get height() + { + return 108; + } + + layout() + { + if (!this.visible) + return; + + if (!this._renderingFrameTimeline.records.length) + return; + + let records = this._renderingFrameTimeline.records; + let startIndex = Math.floor(this.startTime); + let endIndex = Math.min(Math.floor(this.endTime), records.length - 1); + let recordFrameIndex = 0; + + for (let i = startIndex; i <= endIndex; ++i) { + let record = records[i]; + let timelineRecordFrame = this._timelineRecordFrames[recordFrameIndex]; + if (!timelineRecordFrame) + timelineRecordFrame = this._timelineRecordFrames[recordFrameIndex] = new WebInspector.TimelineRecordFrame(this, record); + else + timelineRecordFrame.record = record; + + timelineRecordFrame.refresh(this); + if (!timelineRecordFrame.element.parentNode) + this.element.appendChild(timelineRecordFrame.element); + + timelineRecordFrame.filtered = record[WebInspector.RenderingFrameTimelineOverviewGraph.RecordWasFilteredSymbol] || false; + ++recordFrameIndex; + } + + // Remove the remaining unused TimelineRecordFrames. + for (; recordFrameIndex < this._timelineRecordFrames.length; ++recordFrameIndex) { + this._timelineRecordFrames[recordFrameIndex].record = null; + this._timelineRecordFrames[recordFrameIndex].element.remove(); + } + + this._updateDividers(); + this._updateFrameMarker(); + } + + updateSelectedRecord() + { + if (!this.selectedRecord) { + this._updateFrameMarker(); + return; + } + + const visibleDuration = this.timelineOverview.visibleDuration; + const frameIndex = this.selectedRecord.frameIndex; + + // Reveal a newly selected record if it's outside the visible range. + if (frameIndex < Math.ceil(this.timelineOverview.scrollStartTime) || frameIndex >= this.timelineOverview.scrollStartTime + visibleDuration) { + var scrollStartTime = frameIndex; + if (!this._selectedTimelineRecordFrame || Math.abs(this._selectedTimelineRecordFrame.record.frameIndex - this.selectedRecord.frameIndex) > 1) { + scrollStartTime -= Math.floor(visibleDuration / 2); + scrollStartTime = Math.max(Math.min(scrollStartTime, this.timelineOverview.endTime), this.timelineOverview.startTime); + } + + this.timelineOverview.scrollStartTime = scrollStartTime; + return; + } + + this._updateFrameMarker(); + } + + // Private + + _timelineRecordAdded(event) + { + this._graphHeightSeconds = NaN; + + this.needsLayout(); + } + + _updateDividers() + { + if (this.graphHeightSeconds === 0) + return; + + let overviewGraphHeight = this.height; + + function createDividerAtPosition(framesPerSecond) + { + var secondsPerFrame = 1 / framesPerSecond; + var dividerTop = 1 - secondsPerFrame / this.graphHeightSeconds; + if (dividerTop < 0.01 || dividerTop >= 1) + return; + + var divider = this._framesPerSecondDividerMap.get(framesPerSecond); + if (!divider) { + divider = document.createElement("div"); + divider.classList.add("divider"); + + var label = document.createElement("div"); + label.classList.add("label"); + label.innerText = framesPerSecond + " fps"; + divider.appendChild(label); + + this.element.appendChild(divider); + + this._framesPerSecondDividerMap.set(framesPerSecond, divider); + } + + divider.style.marginTop = (dividerTop * overviewGraphHeight).toFixed(2) + "px"; + } + + createDividerAtPosition.call(this, 60); + createDividerAtPosition.call(this, 30); + } + + _updateFrameMarker() + { + if (this._selectedTimelineRecordFrame) { + this._selectedTimelineRecordFrame.selected = false; + this._selectedTimelineRecordFrame = null; + } + + if (!this.selectedRecord) { + if (this._selectedFrameMarker.parentElement) + this.element.removeChild(this._selectedFrameMarker); + return; + } + + var frameWidth = (1 / this.timelineOverview.secondsPerPixel); + this._selectedFrameMarker.style.width = frameWidth + "px"; + + var markerLeftPosition = this.selectedRecord.frameIndex - this.startTime; + this._selectedFrameMarker.style.left = ((markerLeftPosition / this.timelineOverview.visibleDuration) * 100).toFixed(2) + "%"; + + if (!this._selectedFrameMarker.parentElement) + this.element.appendChild(this._selectedFrameMarker); + + // Find and update the selected frame element. + var index = this._timelineRecordFrames.binaryIndexOf(this.selectedRecord, function(record, frame) { + return frame.record ? record.frameIndex - frame.record.frameIndex : -1; + }); + + console.assert(index >= 0 && index < this._timelineRecordFrames.length, "Selected record not within visible graph duration.", this.selectedRecord); + if (index < 0 || index >= this._timelineRecordFrames.length) + return; + + this._selectedTimelineRecordFrame = this._timelineRecordFrames[index]; + this._selectedTimelineRecordFrame.selected = true; + } + + _mouseClicked(event) + { + var position = event.pageX - this.element.getBoundingClientRect().left; + var frameIndex = Math.floor(position * this.timelineOverview.secondsPerPixel + this.startTime); + if (frameIndex < 0 || frameIndex >= this._renderingFrameTimeline.records.length) + return; + + var newSelectedRecord = this._renderingFrameTimeline.records[frameIndex]; + if (newSelectedRecord[WebInspector.RenderingFrameTimelineOverviewGraph.RecordWasFilteredSymbol]) + return; + + if (this.selectedRecord === newSelectedRecord) + return; + + if (frameIndex >= this.timelineOverview.selectionStartTime && frameIndex < this.timelineOverview.selectionStartTime + this.timelineOverview.selectionDuration) { + this.selectedRecord = newSelectedRecord; + return; + } + + // Clicking a frame outside the current ruler selection changes the selection to include the frame. + this.selectedRecord = newSelectedRecord; + this.timelineOverview.selectionStartTime = frameIndex; + this.timelineOverview.selectionDuration = 1; + } +}; + +WebInspector.RenderingFrameTimelineOverviewGraph.RecordWasFilteredSymbol = Symbol("rendering-frame-overview-graph-record-was-filtered"); + +WebInspector.RenderingFrameTimelineOverviewGraph.MaximumGraphHeightSeconds = 0.037; +WebInspector.RenderingFrameTimelineOverviewGraph.MinimumGraphHeightSeconds = 0.0185; |