1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 } = require("devtools/shared/protocol");
14 } = require("devtools/shared/specs/animation");
16 class AnimationPlayerFront extends FrontClassWithSpec(animationPlayerSpec) {
17 constructor(conn, targetFront, parentFront) {
18 super(conn, targetFront, parentFront);
21 this.before("changed", this.onChanged.bind(this));
26 this.state = this.initialState;
30 * If the AnimationsActor was given a reference to the WalkerActor previously
31 * then calling this getter will return the animation target NodeFront.
33 get animationTargetNodeFront() {
34 if (!this._form.animationTargetNodeActorID) {
38 return this.conn.getFrontByID(this._form.animationTargetNodeActorID);
42 * Getter for the initial state of the player. Up to date states can be
43 * retrieved by calling the getCurrentState method.
47 type: this._form.type,
48 startTime: this._form.startTime,
49 currentTime: this._form.currentTime,
50 playState: this._form.playState,
51 playbackRate: this._form.playbackRate,
52 name: this._form.name,
53 duration: this._form.duration,
54 delay: this._form.delay,
55 endDelay: this._form.endDelay,
56 iterationCount: this._form.iterationCount,
57 iterationStart: this._form.iterationStart,
58 easing: this._form.easing,
59 fill: this._form.fill,
60 direction: this._form.direction,
61 animationTimingFunction: this._form.animationTimingFunction,
62 isRunningOnCompositor: this._form.isRunningOnCompositor,
63 propertyState: this._form.propertyState,
64 documentCurrentTime: this._form.documentCurrentTime,
65 createdTime: this._form.createdTime,
66 currentTimeAtCreated: this._form.currentTimeAtCreated,
67 absoluteValues: this.calculateAbsoluteValues(this._form),
72 * Executed when the AnimationPlayerActor emits a "changed" event. Used to
73 * update the local knowledge of the state.
75 onChanged(partialState) {
76 const { state } = this.reconstructState(partialState);
81 * Refresh the current state of this animation on the client from information
82 * found on the server. Doesn't return anything, just stores the new state.
84 async refreshState() {
85 const data = await this.getCurrentState();
86 if (this.currentStateHasChanged) {
92 * getCurrentState interceptor re-constructs incomplete states since the actor
93 * only sends the values that have changed.
96 this.currentStateHasChanged = false;
97 return super.getCurrentState().then(partialData => {
98 const { state, hasChanged } = this.reconstructState(partialData);
99 this.currentStateHasChanged = hasChanged;
104 reconstructState(data) {
105 let hasChanged = false;
107 for (const key in this.state) {
108 if (typeof data[key] === "undefined") {
109 data[key] = this.state[key];
110 } else if (data[key] !== this.state[key]) {
115 data.absoluteValues = this.calculateAbsoluteValues(data);
116 return { state: data, hasChanged };
119 calculateAbsoluteValues(data) {
123 currentTimeAtCreated,
132 const toRate = v => v / Math.abs(playbackRate);
133 const isPositivePlaybackRate = playbackRate > 0;
134 let absoluteDelay = 0;
135 let absoluteEndDelay = 0;
136 let isDelayFilled = false;
137 let isEndDelayFilled = false;
139 if (isPositivePlaybackRate) {
140 absoluteDelay = toRate(delay);
141 absoluteEndDelay = toRate(endDelay);
142 isDelayFilled = fill === "both" || fill === "backwards";
143 isEndDelayFilled = fill === "both" || fill === "forwards";
145 absoluteDelay = toRate(endDelay);
146 absoluteEndDelay = toRate(delay);
147 isDelayFilled = fill === "both" || fill === "forwards";
148 isEndDelayFilled = fill === "both" || fill === "backwards";
153 if (duration === Infinity) {
154 // Set endTime so as to enable the scrubber with keeping the consinstency of UI
155 // even the duration was Infinity. In case of delay is longer than zero, handle
156 // the graph duration as double of the delay amount. In case of no delay, handle
157 // the duration as 1ms which is short enough so as to make the scrubber movable
158 // and the limited duration is prioritized.
159 endTime = absoluteDelay > 0 ? absoluteDelay * 2 : 1;
163 toRate(duration * (iterationCount || 1)) +
167 const absoluteCreatedTime = isPositivePlaybackRate
169 : createdTime - endTime;
170 const absoluteCurrentTimeAtCreated = isPositivePlaybackRate
171 ? currentTimeAtCreated
172 : endTime - currentTimeAtCreated;
173 const animationCurrentTime = isPositivePlaybackRate
175 : endTime - currentTime;
176 const absoluteCurrentTime =
177 absoluteCreatedTime + toRate(animationCurrentTime);
178 const absoluteStartTime = absoluteCreatedTime + Math.min(absoluteDelay, 0);
179 const absoluteStartTimeAtCreated =
180 absoluteCreatedTime + absoluteCurrentTimeAtCreated;
181 // To show whole graph with endDelay, we add negative endDelay amount to endTime.
182 const endTimeWithNegativeEndDelay = endTime - Math.min(absoluteEndDelay, 0);
183 const absoluteEndTime = absoluteCreatedTime + endTimeWithNegativeEndDelay;
186 createdTime: absoluteCreatedTime,
187 currentTime: absoluteCurrentTime,
188 currentTimeAtCreated: absoluteCurrentTimeAtCreated,
189 delay: absoluteDelay,
190 endDelay: absoluteEndDelay,
191 endTime: absoluteEndTime,
194 startTime: absoluteStartTime,
195 startTimeAtCreated: absoluteStartTimeAtCreated,
200 exports.AnimationPlayerFront = AnimationPlayerFront;
201 registerFront(AnimationPlayerFront);
203 class AnimationsFront extends FrontClassWithSpec(animationsSpec) {
204 constructor(client, targetFront, parentFront) {
205 super(client, targetFront, parentFront);
207 // Attribute name from which to retrieve the actorID out of the target actor's form
208 this.formAttributeName = "animationsActor";
212 exports.AnimationsFront = AnimationsFront;
213 registerFront(AnimationsFront);