| /* |
| * Copyright (C) 2018 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. |
| */ |
| |
| WI.DOMEventsBreakdownView = class DOMEventsBreakdownView extends WI.View |
| { |
| constructor(domNodeOrEvents, {includeGraph} = {}) |
| { |
| console.assert(domNodeOrEvents instanceof WI.DOMNode || Array.isArray(domNodeOrEvents)); |
| |
| super(); |
| |
| if (domNodeOrEvents instanceof WI.DOMNode) { |
| this._domNode = domNodeOrEvents; |
| this._domNode.addEventListener(WI.DOMNode.Event.DidFireEvent, this._handleDOMNodeDidFireEvent, this); |
| if (this._domNode.canEnterPowerEfficientPlaybackState()) |
| this._domNode.addEventListener(WI.DOMNode.Event.PowerEfficientPlaybackStateChanged, this._handleDOMNodePowerEfficientPlaybackStateChanged, this); |
| |
| this._domEvents = null; |
| } else { |
| this._domNode = null; |
| this._domEvents = domNodeOrEvents; |
| } |
| |
| this._includeGraph = includeGraph || false; |
| |
| this._tableBodyElement = null; |
| |
| this.element.classList.add("dom-events-breakdown"); |
| } |
| |
| // Protected |
| |
| initialLayout() |
| { |
| super.initialLayout(); |
| |
| let tableElement = this.element.appendChild(document.createElement("table")); |
| |
| let headElement = tableElement.appendChild(document.createElement("thead")); |
| |
| let headRowElement = headElement.appendChild(document.createElement("tr")); |
| |
| let eventHeadCell = headRowElement.appendChild(document.createElement("th")); |
| eventHeadCell.textContent = WI.UIString("Event"); |
| |
| if (this._includeGraph) |
| headRowElement.appendChild(document.createElement("th")); |
| |
| let timeHeadCell = headRowElement.appendChild(document.createElement("th")); |
| timeHeadCell.classList.add("time"); |
| timeHeadCell.textContent = WI.UIString("Time"); |
| |
| let originatorHeadCell = headRowElement.appendChild(document.createElement("th")); |
| originatorHeadCell.classList.add("originator"); |
| originatorHeadCell.textContent = WI.UIString("Originator"); |
| |
| this._tableBodyElement = tableElement.appendChild(document.createElement("tbody")); |
| } |
| |
| layout() |
| { |
| if (this.layoutReason !== WI.View.LayoutReason.Dirty) |
| return; |
| |
| this._tableBodyElement.removeChildren(); |
| |
| console.assert(this._domEvents || (this._domNode && this._domNode.domEvents)); |
| let domEvents = this._domEvents || this._domNode.domEvents; |
| let startTimestamp = domEvents[0].timestamp; |
| let endTimestamp = domEvents.lastValue.timestamp; |
| let totalTime = endTimestamp - startTimestamp; |
| let styleAttribute = WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR ? "left" : "right"; |
| |
| function percentOfTotalTime(time) { |
| return time / totalTime * 100; |
| } |
| |
| let fullscreenRanges = []; |
| let fullscreenDOMEvents = WI.DOMNode.getFullscreenDOMEvents(domEvents); |
| for (let fullscreenDOMEvent of fullscreenDOMEvents) { |
| let {enabled} = fullscreenDOMEvent.data; |
| if (enabled || !fullscreenRanges.length) { |
| fullscreenRanges.push({ |
| startTimestamp: enabled ? fullscreenDOMEvent.timestamp : startTimestamp, |
| }); |
| } |
| fullscreenRanges.lastValue.endTimestamp = (enabled && fullscreenDOMEvent === fullscreenDOMEvents.lastValue) ? endTimestamp : fullscreenDOMEvent.timestamp; |
| if (fullscreenDOMEvent.originator) |
| fullscreenRanges.lastValue.originator = fullscreenDOMEvent.originator; |
| } |
| |
| let powerEfficientPlaybackRanges = this._domNode ? this._domNode.powerEfficientPlaybackRanges : []; |
| |
| for (let domEvent of domEvents) { |
| let rowElement = this._tableBodyElement.appendChild(document.createElement("tr")); |
| |
| let nameCell = rowElement.appendChild(document.createElement("td")); |
| nameCell.classList.add("name"); |
| nameCell.textContent = domEvent.eventName; |
| |
| if (this._includeGraph) { |
| let graphCell = rowElement.appendChild(document.createElement("td")); |
| graphCell.classList.add("graph"); |
| |
| let fullscreenRange = fullscreenRanges.find((range) => domEvent.timestamp >= range.startTimestamp && domEvent.timestamp <= range.endTimestamp); |
| if (fullscreenRange) { |
| let fullscreenArea = graphCell.appendChild(document.createElement("div")); |
| fullscreenArea.classList.add("area", "fullscreen"); |
| fullscreenArea.style.setProperty(styleAttribute, percentOfTotalTime(fullscreenRange.startTimestamp - startTimestamp) + "%"); |
| fullscreenArea.style.setProperty("width", percentOfTotalTime(fullscreenRange.endTimestamp - fullscreenRange.startTimestamp) + "%"); |
| |
| if (fullscreenRange.originator) |
| fullscreenArea.title = WI.UIString("Full-Screen from \u201C%s\u201D").format(fullscreenRange.originator.displayName); |
| else |
| fullscreenArea.title = WI.UIString("Full-Screen"); |
| } |
| |
| let powerEfficientPlaybackRange = powerEfficientPlaybackRanges.find((range) => domEvent.timestamp >= range.startTimestamp && domEvent.timestamp <= range.endTimestamp); |
| if (powerEfficientPlaybackRange) { |
| let powerEfficientPlaybackArea = graphCell.appendChild(document.createElement("div")); |
| powerEfficientPlaybackArea.classList.add("area", "power-efficient-playback"); |
| powerEfficientPlaybackArea.title = WI.UIString("Power Efficient Playback"); |
| powerEfficientPlaybackArea.style.setProperty(styleAttribute, percentOfTotalTime(powerEfficientPlaybackRange.startTimestamp - startTimestamp) + "%"); |
| powerEfficientPlaybackArea.style.setProperty("width", percentOfTotalTime(powerEfficientPlaybackRange.endTimestamp - powerEfficientPlaybackRange.startTimestamp) + "%"); |
| } |
| |
| let graphImage = graphCell.appendChild(document.createElement("img")); |
| graphImage.style.setProperty(styleAttribute, `calc(${percentOfTotalTime(domEvent.timestamp - startTimestamp)}% - (var(--img-size) / 2))`); |
| if (WI.DOMNode.isPlayEvent(domEvent.eventName)) |
| graphImage.src = "Images/EventPlay.svg"; |
| else if (WI.DOMNode.isPauseEvent(domEvent.eventName)) |
| graphImage.src = "Images/EventPause.svg"; |
| else if (WI.DOMNode.isStopEvent(domEvent.eventName)) |
| graphImage.src = "Images/EventStop.svg"; |
| else |
| graphImage.src = "Images/EventProcessing.svg"; |
| } |
| |
| let timeCell = rowElement.appendChild(document.createElement("td")); |
| timeCell.classList.add("time"); |
| |
| const higherResolution = true; |
| timeCell.textContent = Number.secondsToString(domEvent.timestamp, higherResolution); |
| |
| let originatorCell = rowElement.appendChild(document.createElement("td")); |
| originatorCell.classList.add("originator"); |
| if (domEvent.originator) { |
| originatorCell.appendChild(WI.linkifyNodeReference(domEvent.originator)); |
| |
| rowElement.classList.add("inherited"); |
| this.element.classList.add("has-inherited"); |
| } |
| } |
| } |
| |
| // Private |
| |
| _handleDOMNodeDidFireEvent(event) |
| { |
| this.needsLayout(); |
| } |
| |
| _handleDOMNodePowerEfficientPlaybackStateChanged(event) |
| { |
| this.needsLayout(); |
| } |
| }; |