blob: 25ff3d6695d4be842afa64f492c373df2ddf0e62 [file] [log] [blame]
/*
* 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();
}
};