Added MacOS SDK
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* 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.MediaTimelineRecord = class MediaTimelineRecord extends WI.TimelineRecord
|
||||
{
|
||||
constructor(eventType, domNodeOrInfo, {trackingAnimationId, animationName, transitionProperty} = {})
|
||||
{
|
||||
console.assert(Object.values(MediaTimelineRecord.EventType).includes(eventType));
|
||||
console.assert(domNodeOrInfo instanceof WI.DOMNode || (!isEmptyObject(domNodeOrInfo) && domNodeOrInfo.displayName && domNodeOrInfo.cssPath));
|
||||
|
||||
super(WI.TimelineRecord.Type.Media);
|
||||
|
||||
this._eventType = eventType;
|
||||
this._domNode = domNodeOrInfo;
|
||||
this._domNodeDisplayName = domNodeOrInfo?.displayName;
|
||||
this._domNodeCSSPath = domNodeOrInfo instanceof WI.DOMNode ? WI.cssPath(domNodeOrInfo, {full: true}) : domNodeOrInfo?.cssPath;
|
||||
|
||||
// Web Animation
|
||||
console.assert(trackingAnimationId === undefined || typeof trackingAnimationId === "string");
|
||||
this._trackingAnimationId = trackingAnimationId || null;
|
||||
|
||||
// CSS Web Animation
|
||||
console.assert(animationName === undefined || typeof animationName === "string");
|
||||
console.assert(transitionProperty === undefined || typeof transitionProperty === "string");
|
||||
this._animationName = animationName || null;
|
||||
this._transitionProperty = transitionProperty || null;
|
||||
|
||||
this._timestamps = [];
|
||||
this._activeStartTime = NaN;
|
||||
}
|
||||
|
||||
// Import / Export
|
||||
|
||||
static async fromJSON(json)
|
||||
{
|
||||
let {eventType, domNodeDisplayName, domNodeCSSPath, animationName, transitionProperty, timestamps} = json;
|
||||
|
||||
let documentNode = null;
|
||||
if (InspectorBackend.hasDomain("DOM"))
|
||||
documentNode = await new Promise((resolve) => WI.domManager.requestDocument(resolve));
|
||||
|
||||
let domNode = null;
|
||||
if (documentNode && domNodeCSSPath) {
|
||||
try {
|
||||
let nodeId = await documentNode.querySelector(domNodeCSSPath);
|
||||
if (nodeId)
|
||||
domNode = WI.domManager.nodeForId(nodeId);
|
||||
} catch { }
|
||||
}
|
||||
if (!domNode) {
|
||||
domNode = {
|
||||
displayName: domNodeDisplayName,
|
||||
cssPath: domNodeCSSPath,
|
||||
};
|
||||
}
|
||||
|
||||
let record = new MediaTimelineRecord(eventType, domNode, {animationName, transitionProperty});
|
||||
|
||||
if (Array.isArray(timestamps) && timestamps.length) {
|
||||
record._timestamps = [];
|
||||
for (let item of timestamps) {
|
||||
if (item.type === MediaTimelineRecord.TimestampType.MediaElementDOMEvent) {
|
||||
if (documentNode && item.originatorCSSPath) {
|
||||
try {
|
||||
let nodeId = await documentNode.querySelector(item.originatorCSSPath);
|
||||
if (nodeId)
|
||||
item.originator = WI.domManager.nodeForId(nodeId);
|
||||
} catch { }
|
||||
if (!item.originator) {
|
||||
item.originator = {
|
||||
displayName: item.originatorDisplayName,
|
||||
cssPath: item.originatorCSSPath,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
record._timestamps.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
toJSON()
|
||||
{
|
||||
let json = {
|
||||
eventType: this._eventType,
|
||||
domNodeDisplayName: this._domNodeDisplayName,
|
||||
domNodeCSSPath: this._domNodeCSSPath,
|
||||
};
|
||||
|
||||
if (this._animationName)
|
||||
json.animationName = this._animationName;
|
||||
|
||||
if (this._transitionProperty)
|
||||
json.transitionProperty = this._transitionProperty;
|
||||
|
||||
if (this._timestamps.length) {
|
||||
json.timestamps = this._timestamps.map((item) => {
|
||||
if (item.type === MediaTimelineRecord.TimestampType.MediaElementDOMEvent && item.originator instanceof WI.DOMNode)
|
||||
delete item.originator;
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
get eventType() { return this._eventType; }
|
||||
get domNode() { return this._domNode; }
|
||||
get trackingAnimationId() { return this._trackingAnimationId; }
|
||||
get timestamps() { return this._timestamps; }
|
||||
get activeStartTime() { return this._activeStartTime; }
|
||||
|
||||
get updatesDynamically()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
get usesActiveStartTime()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
get displayName()
|
||||
{
|
||||
switch (this._eventType) {
|
||||
case MediaTimelineRecord.EventType.CSSAnimation:
|
||||
return this._animationName;
|
||||
|
||||
case MediaTimelineRecord.EventType.CSSTransition:
|
||||
return this._transitionProperty;
|
||||
|
||||
case MediaTimelineRecord.EventType.MediaElement:
|
||||
return WI.UIString("Media Element");
|
||||
}
|
||||
|
||||
console.error("Unknown media record event type: ", this._eventType, this);
|
||||
return WI.UIString("Media Event");
|
||||
}
|
||||
|
||||
get subtitle()
|
||||
{
|
||||
switch (this._eventType) {
|
||||
case MediaTimelineRecord.EventType.CSSAnimation:
|
||||
return WI.UIString("CSS Animation");
|
||||
|
||||
case MediaTimelineRecord.EventType.CSSTransition:
|
||||
return WI.UIString("CSS Transition");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
saveIdentityToCookie(cookie)
|
||||
{
|
||||
super.saveIdentityToCookie(cookie);
|
||||
|
||||
cookie["media-timeline-record-event-type"] = this._eventType;
|
||||
cookie["media-timeline-record-dom-node"] = this._domNode instanceof WI.DOMNode ? this._domNode.path() : this._domNode;
|
||||
if (this._animationName)
|
||||
cookie["media-timeline-record-animation-name"] = this._animationName;
|
||||
if (this._transitionProperty)
|
||||
cookie["media-timeline-record-transition-property"] = this._transitionProperty;
|
||||
}
|
||||
|
||||
// TimelineManager
|
||||
|
||||
updateAnimationState(timestamp, animationState)
|
||||
{
|
||||
console.assert(this._eventType === MediaTimelineRecord.EventType.CSSAnimation || this._eventType === MediaTimelineRecord.EventType.CSSTransition);
|
||||
console.assert(!this._timestamps.length || timestamp > this._timestamps.lastValue.timestamp);
|
||||
|
||||
let type;
|
||||
switch (animationState) {
|
||||
case InspectorBackend.Enum.Animation.AnimationState.Ready:
|
||||
type = MediaTimelineRecord.TimestampType.CSSAnimationReady;
|
||||
break;
|
||||
case InspectorBackend.Enum.Animation.AnimationState.Delayed:
|
||||
type = MediaTimelineRecord.TimestampType.CSSAnimationDelay;
|
||||
break;
|
||||
case InspectorBackend.Enum.Animation.AnimationState.Active:
|
||||
type = MediaTimelineRecord.TimestampType.CSSAnimationActive;
|
||||
break;
|
||||
case InspectorBackend.Enum.Animation.AnimationState.Canceled:
|
||||
type = MediaTimelineRecord.TimestampType.CSSAnimationCancel;
|
||||
break;
|
||||
case InspectorBackend.Enum.Animation.AnimationState.Done:
|
||||
type = MediaTimelineRecord.TimestampType.CSSAnimationDone;
|
||||
break;
|
||||
}
|
||||
console.assert(type);
|
||||
|
||||
this._timestamps.push({type, timestamp});
|
||||
|
||||
this._updateTimes();
|
||||
}
|
||||
|
||||
addDOMEvent(timestamp, domEvent)
|
||||
{
|
||||
console.assert(this._eventType === MediaTimelineRecord.EventType.MediaElement);
|
||||
console.assert(!this._timestamps.length || timestamp > this._timestamps.lastValue.timestamp);
|
||||
|
||||
let data = {
|
||||
type: MediaTimelineRecord.TimestampType.MediaElementDOMEvent,
|
||||
timestamp,
|
||||
eventName: domEvent.eventName,
|
||||
};
|
||||
if (domEvent.originator instanceof WI.DOMNode) {
|
||||
data.originator = domEvent.originator;
|
||||
data.originatorDisplayName = data.originator.displayName;
|
||||
data.originatorCSSPath = WI.cssPath(data.originator, {full: true});
|
||||
}
|
||||
if (!isEmptyObject(domEvent.data))
|
||||
data.data = domEvent.data;
|
||||
this._timestamps.push(data);
|
||||
|
||||
this._updateTimes();
|
||||
}
|
||||
|
||||
powerEfficientPlaybackStateChanged(timestamp, isPowerEfficient)
|
||||
{
|
||||
console.assert(this._eventType === MediaTimelineRecord.EventType.MediaElement);
|
||||
console.assert(!this._timestamps.length || timestamp > this._timestamps.lastValue.timestamp);
|
||||
|
||||
this._timestamps.push({
|
||||
type: MediaTimelineRecord.TimestampType.MediaElementPowerEfficientPlaybackStateChange,
|
||||
timestamp,
|
||||
isPowerEfficient,
|
||||
});
|
||||
|
||||
this._updateTimes();
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_updateTimes()
|
||||
{
|
||||
let oldStartTime = this.startTime;
|
||||
let oldEndTime = this.endTime;
|
||||
|
||||
let firstItem = this._timestamps[0];
|
||||
let lastItem = this._timestamps.lastValue;
|
||||
|
||||
if (isNaN(this._startTime))
|
||||
this._startTime = firstItem.timestamp;
|
||||
|
||||
if (isNaN(this._activeStartTime)) {
|
||||
if (this._eventType === MediaTimelineRecord.EventType.MediaElement)
|
||||
this._activeStartTime = firstItem.timestamp;
|
||||
else if (firstItem.type === MediaTimelineRecord.TimestampType.CSSAnimationActive)
|
||||
this._activeStartTime = firstItem.timestamp;
|
||||
}
|
||||
|
||||
switch (lastItem.type) {
|
||||
case MediaTimelineRecord.TimestampType.CSSAnimationCancel:
|
||||
case MediaTimelineRecord.TimestampType.CSSAnimationDone:
|
||||
this._endTime = lastItem.timestamp;
|
||||
break;
|
||||
|
||||
case MediaTimelineRecord.TimestampType.MediaElementDOMEvent:
|
||||
if (WI.DOMNode.isPlayEvent(lastItem.eventName))
|
||||
this._endTime = NaN;
|
||||
else if (!isNaN(this._endTime) || WI.DOMNode.isPauseEvent(lastItem.eventName) || WI.DOMNode.isStopEvent(lastItem.eventName))
|
||||
this._endTime = lastItem.timestamp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.startTime !== oldStartTime || this.endTime !== oldEndTime)
|
||||
this.dispatchEventToListeners(WI.TimelineRecord.Event.Updated);
|
||||
}
|
||||
};
|
||||
|
||||
WI.MediaTimelineRecord.EventType = {
|
||||
CSSAnimation: "css-animation",
|
||||
CSSTransition: "css-transition",
|
||||
MediaElement: "media-element",
|
||||
};
|
||||
|
||||
WI.MediaTimelineRecord.TimestampType = {
|
||||
CSSAnimationReady: "css-animation-ready",
|
||||
CSSAnimationDelay: "css-animation-delay",
|
||||
CSSAnimationActive: "css-animation-active",
|
||||
CSSAnimationCancel: "css-animation-cancel",
|
||||
CSSAnimationDone: "css-animation-done",
|
||||
// CSS transitions share the same timestamp types.
|
||||
|
||||
MediaElementDOMEvent: "media-element-dom-event",
|
||||
MediaElementPowerEfficientPlaybackStateChange: "media-element-power-efficient-playback-state-change",
|
||||
};
|
||||
Reference in New Issue
Block a user