Bug 1265718 - Decouple AnimationPlayerFront from AnimationPlayerActor;r=jryans
authorEddy Bruel <ejpbruel@mozilla.com>
Tue, 24 May 2016 11:27:38 +0200
changeset 298263 e8f4f77bd99eee8e95262779c90235ce5aaaafe4
parent 298262 00f9eb3e72e805caebd204b780dc904877cab590
child 298264 3ffcd4e5783aeda3c4fa1d260634e63f40e3159a
push id19345
push userejpbruel@mozilla.com
push dateTue, 24 May 2016 09:27:50 +0000
treeherderfx-team@e8f4f77bd99e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs1265718
milestone49.0a1
Bug 1265718 - Decouple AnimationPlayerFront from AnimationPlayerActor;r=jryans
devtools/server/actors/animation.js
devtools/shared/fronts/animation.js
devtools/shared/fronts/moz.build
devtools/shared/specs/animation.js
devtools/shared/specs/moz.build
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -28,16 +28,18 @@
 const {Cu} = require("chrome");
 const promise = require("promise");
 const {Task} = require("devtools/shared/task");
 const protocol = require("devtools/shared/protocol");
 const {ActorClass, Actor, FrontClass, Front,
        Arg, method, RetVal, types} = protocol;
 // Make sure the nodeActor type is know here.
 const {NodeActor} = require("devtools/server/actors/inspector");
+const {AnimationPlayerFront} = require("devtools/shared/fronts/animation");
+const {animationPlayerSpec} = require("devtools/shared/specs/animation");
 const events = require("sdk/event/core");
 
 // Types of animations.
 const ANIMATION_TYPES = {
   CSS_ANIMATION: "cssanimation",
   CSS_TRANSITION: "csstransition",
   SCRIPT_ANIMATION: "scriptanimation",
   UNKNOWN: "unknown"
@@ -48,26 +50,17 @@ exports.ANIMATION_TYPES = ANIMATION_TYPE
  * The AnimationPlayerActor provides information about a given animation: its
  * startTime, currentTime, current state, etc.
  *
  * Since the state of a player changes as the animation progresses it is often
  * useful to call getCurrentState at regular intervals to get the current state.
  *
  * This actor also allows playing, pausing and seeking the animation.
  */
-var AnimationPlayerActor = ActorClass({
-  typeName: "animationplayer",
-
-  events: {
-    "changed": {
-      type: "changed",
-      state: Arg(0, "json")
-    }
-  },
-
+var AnimationPlayerActor = protocol.ActorClassWithSpec(animationPlayerSpec, {
   /**
    * @param {AnimationsActor} The main AnimationsActor instance
    * @param {AnimationPlayer} The player object returned by getAnimationPlayers
    */
   initialize: function (animationsActor, player) {
     Actor.prototype.initialize.call(this, animationsActor.conn);
 
     this.onAnimationMutation = this.onAnimationMutation.bind(this);
@@ -136,17 +129,17 @@ var AnimationPlayerActor = ActorClass({
   get window() {
     return this.node.ownerDocument.defaultView;
   },
 
   /**
    * Release the actor, when it isn't needed anymore.
    * Protocol.js uses this release method to call the destroy method.
    */
-  release: method(function () {}, {release: true}),
+  release: function () {},
 
   form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     let data = this.getCurrentState();
     data.actor = this.actorID;
@@ -308,17 +301,17 @@ var AnimationPlayerActor = ActorClass({
    * Get the current state of the AnimationPlayer (currentTime, playState, ...).
    * Note that the initial state is returned as the form of this actor when it
    * is initialized.
    * This protocol method only returns a trimed down version of this state in
    * case some properties haven't changed since last time (since the front can
    * reconstruct those). If you want the full state, use the getState method.
    * @return {Object}
    */
-  getCurrentState: method(function () {
+  getCurrentState: function () {
     let newState = this.getState();
 
     // If we've saved a state before, compare and only send what has changed.
     // It's expected of the front to also save old states to re-construct the
     // full state when an incomplete one is received.
     // This is to minimize protocol traffic.
     let sentState = {};
     if (this.currentState) {
@@ -329,22 +322,17 @@ var AnimationPlayerActor = ActorClass({
         }
       }
     } else {
       sentState = newState;
     }
     this.currentState = newState;
 
     return sentState;
-  }, {
-    request: {},
-    response: {
-      data: RetVal("json")
-    }
-  }),
+  },
 
   /**
    * Executed when the current animation changes, used to emit the new state
    * the the front.
    */
   onAnimationMutation: function (mutations) {
     let isCurrentAnimation = animation => animation === this.player;
     let hasCurrentAnimation = animations => animations.some(isCurrentAnimation);
@@ -375,218 +363,83 @@ var AnimationPlayerActor = ActorClass({
     if (hasChanged) {
       events.emit(this, "changed", this.getCurrentState());
     }
   },
 
   /**
    * Pause the player.
    */
-  pause: method(function () {
+  pause: function () {
     this.player.pause();
     return this.player.ready;
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Play the player.
    * This method only returns when the animation has left its pending state.
    */
-  play: method(function () {
+  play: function () {
     this.player.play();
     return this.player.ready;
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Simply exposes the player ready promise.
    *
    * When an animation is created/paused then played, there's a short time
    * during which its playState is pending, before being set to running.
    *
    * If you either created a new animation using the Web Animations API or
    * paused/played an existing one, and then want to access the playState, you
    * might be interested to call this method.
    * This is especially important for tests.
    */
-  ready: method(function () {
+  ready: function () {
     return this.player.ready;
-  }, {
-    request: {},
-    response: {}
-  }),
+  },
 
   /**
    * Set the current time of the animation player.
    */
-  setCurrentTime: method(function (currentTime) {
+  setCurrentTime: function (currentTime) {
     this.player.currentTime = currentTime * this.player.playbackRate;
-  }, {
-    request: {
-      currentTime: Arg(0, "number")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Set the playback rate of the animation player.
    */
-  setPlaybackRate: method(function (playbackRate) {
+  setPlaybackRate: function (playbackRate) {
     this.player.playbackRate = playbackRate;
-  }, {
-    request: {
-      currentTime: Arg(0, "number")
-    },
-    response: {}
-  }),
+  },
 
   /**
    * Get data about the keyframes of this animation player.
    * @return {Object} Returns a list of frames, each frame containing the list
    * animated properties as well as the frame's offset.
    */
-  getFrames: method(function () {
+  getFrames: function () {
     return this.player.effect.getKeyframes();
-  }, {
-    request: {},
-    response: {
-      frames: RetVal("json")
-    }
-  }),
+  },
 
   /**
    * Get data about the animated properties of this animation player.
    * @return {Array} Returns a list of animated properties.
    * Each property contains a list of values and their offsets
    */
-  getProperties: method(function () {
+  getProperties: function () {
     return this.player.effect.getProperties().map(property => {
       return {name: property.property, values: property.values};
     });
-  }, {
-    request: {},
-    response: {
-      properties: RetVal("array:json")
-    }
-  })
+  }
 });
 
 exports.AnimationPlayerActor = AnimationPlayerActor;
 
-var AnimationPlayerFront = FrontClass(AnimationPlayerActor, {
-  initialize: function (conn, form, detail, ctx) {
-    Front.prototype.initialize.call(this, conn, form, detail, ctx);
-
-    this.state = {};
-  },
-
-  form: function (form, detail) {
-    if (detail === "actorid") {
-      this.actorID = form;
-      return;
-    }
-    this._form = form;
-    this.state = this.initialState;
-  },
-
-  destroy: function () {
-    Front.prototype.destroy.call(this);
-  },
-
-  /**
-   * If the AnimationsActor was given a reference to the WalkerActor previously
-   * then calling this getter will return the animation target NodeFront.
-   */
-  get animationTargetNodeFront() {
-    if (!this._form.animationTargetNodeActorID) {
-      return null;
-    }
-
-    return this.conn.getActor(this._form.animationTargetNodeActorID);
-  },
-
-  /**
-   * Getter for the initial state of the player. Up to date states can be
-   * retrieved by calling the getCurrentState method.
-   */
-  get initialState() {
-    return {
-      type: this._form.type,
-      startTime: this._form.startTime,
-      previousStartTime: this._form.previousStartTime,
-      currentTime: this._form.currentTime,
-      playState: this._form.playState,
-      playbackRate: this._form.playbackRate,
-      name: this._form.name,
-      duration: this._form.duration,
-      delay: this._form.delay,
-      endDelay: this._form.endDelay,
-      iterationCount: this._form.iterationCount,
-      iterationStart: this._form.iterationStart,
-      isRunningOnCompositor: this._form.isRunningOnCompositor,
-      propertyState: this._form.propertyState,
-      documentCurrentTime: this._form.documentCurrentTime
-    };
-  },
-
-  /**
-   * Executed when the AnimationPlayerActor emits a "changed" event. Used to
-   * update the local knowledge of the state.
-   */
-  onChanged: protocol.preEvent("changed", function (partialState) {
-    let {state} = this.reconstructState(partialState);
-    this.state = state;
-  }),
-
-  /**
-   * Refresh the current state of this animation on the client from information
-   * found on the server. Doesn't return anything, just stores the new state.
-   */
-  refreshState: Task.async(function* () {
-    let data = yield this.getCurrentState();
-    if (this.currentStateHasChanged) {
-      this.state = data;
-    }
-  }),
-
-  /**
-   * getCurrentState interceptor re-constructs incomplete states since the actor
-   * only sends the values that have changed.
-   */
-  getCurrentState: protocol.custom(function () {
-    this.currentStateHasChanged = false;
-    return this._getCurrentState().then(partialData => {
-      let {state, hasChanged} = this.reconstructState(partialData);
-      this.currentStateHasChanged = hasChanged;
-      return state;
-    });
-  }, {
-    impl: "_getCurrentState"
-  }),
-
-  reconstructState: function (data) {
-    let hasChanged = false;
-
-    for (let key in this.state) {
-      if (typeof data[key] === "undefined") {
-        data[key] = this.state[key];
-      } else if (data[key] !== this.state[key]) {
-        hasChanged = true;
-      }
-    }
-
-    return {state: data, hasChanged};
-  }
-});
-
-/**
+ /**
  * Sent with the 'mutations' event as part of an array of changes, used to
  * inform fronts of the type of change that occured.
  */
 types.addDictType("animationMutationChange", {
   // The type of change ("added" or "removed").
   type: "string",
   // The changed AnimationPlayerActor.
   player: "animationplayer"
new file mode 100644
--- /dev/null
+++ b/devtools/shared/fronts/animation.js
@@ -0,0 +1,121 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const {
+  Front,
+  FrontClassWithSpec,
+  custom,
+  preEvent
+} = require("devtools/shared/protocol");
+const { animationPlayerSpec } = require("devtools/shared/specs/animation");
+const { Task } = require("devtools/shared/task");
+
+const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
+  initialize: function (conn, form, detail, ctx) {
+    Front.prototype.initialize.call(this, conn, form, detail, ctx);
+
+    this.state = {};
+  },
+
+  form: function (form, detail) {
+    if (detail === "actorid") {
+      this.actorID = form;
+      return;
+    }
+    this._form = form;
+    this.state = this.initialState;
+  },
+
+  destroy: function () {
+    Front.prototype.destroy.call(this);
+  },
+
+  /**
+   * If the AnimationsActor was given a reference to the WalkerActor previously
+   * then calling this getter will return the animation target NodeFront.
+   */
+  get animationTargetNodeFront() {
+    if (!this._form.animationTargetNodeActorID) {
+      return null;
+    }
+
+    return this.conn.getActor(this._form.animationTargetNodeActorID);
+  },
+
+  /**
+   * Getter for the initial state of the player. Up to date states can be
+   * retrieved by calling the getCurrentState method.
+   */
+  get initialState() {
+    return {
+      type: this._form.type,
+      startTime: this._form.startTime,
+      previousStartTime: this._form.previousStartTime,
+      currentTime: this._form.currentTime,
+      playState: this._form.playState,
+      playbackRate: this._form.playbackRate,
+      name: this._form.name,
+      duration: this._form.duration,
+      delay: this._form.delay,
+      endDelay: this._form.endDelay,
+      iterationCount: this._form.iterationCount,
+      iterationStart: this._form.iterationStart,
+      isRunningOnCompositor: this._form.isRunningOnCompositor,
+      propertyState: this._form.propertyState,
+      documentCurrentTime: this._form.documentCurrentTime
+    };
+  },
+
+  /**
+   * Executed when the AnimationPlayerActor emits a "changed" event. Used to
+   * update the local knowledge of the state.
+   */
+  onChanged: preEvent("changed", function (partialState) {
+    let {state} = this.reconstructState(partialState);
+    this.state = state;
+  }),
+
+  /**
+   * Refresh the current state of this animation on the client from information
+   * found on the server. Doesn't return anything, just stores the new state.
+   */
+  refreshState: Task.async(function* () {
+    let data = yield this.getCurrentState();
+    if (this.currentStateHasChanged) {
+      this.state = data;
+    }
+  }),
+
+  /**
+   * getCurrentState interceptor re-constructs incomplete states since the actor
+   * only sends the values that have changed.
+   */
+  getCurrentState: custom(function () {
+    this.currentStateHasChanged = false;
+    return this._getCurrentState().then(partialData => {
+      let {state, hasChanged} = this.reconstructState(partialData);
+      this.currentStateHasChanged = hasChanged;
+      return state;
+    });
+  }, {
+    impl: "_getCurrentState"
+  }),
+
+  reconstructState: function (data) {
+    let hasChanged = false;
+
+    for (let key in this.state) {
+      if (typeof data[key] === "undefined") {
+        data[key] = this.state[key];
+      } else if (data[key] !== this.state[key]) {
+        hasChanged = true;
+      }
+    }
+
+    return {state: data, hasChanged};
+  }
+});
+
+exports.AnimationPlayerFront = AnimationPlayerFront;
--- a/devtools/shared/fronts/moz.build
+++ b/devtools/shared/fronts/moz.build
@@ -1,13 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DevToolsModules(
+    'animation.js',
     'highlighters.js',
     'inspector.js',
     'storage.js',
     'styles.js',
     'stylesheets.js'
 )
new file mode 100644
--- /dev/null
+++ b/devtools/shared/specs/animation.js
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const { Arg, RetVal, generateActorSpec } = require("devtools/shared/protocol");
+
+const animationPlayerSpec = generateActorSpec({
+  typeName: "animationplayer",
+
+  events: {
+    "changed": {
+      type: "changed",
+      state: Arg(0, "json")
+    }
+  },
+
+  methods: {
+    release: { release: true },
+    getCurrentState: {
+      request: {},
+      response: {
+        data: RetVal("json")
+      }
+    },
+    pause: {
+      request: {},
+      response: {}
+    },
+    play: {
+      request: {},
+      response: {}
+    },
+    ready: {
+      request: {},
+      response: {}
+    },
+    setCurrentTime: {
+      request: {
+        currentTime: Arg(0, "number")
+      },
+      response: {}
+    },
+    setPlaybackRate: {
+      request: {
+        currentTime: Arg(0, "number")
+      },
+      response: {}
+    },
+    getFrames: {
+      request: {},
+      response: {
+        frames: RetVal("json")
+      }
+    },
+    getProperties: {
+      request: {},
+      response: {
+        properties: RetVal("array:json")
+      }
+    }
+  }
+});
+
+exports.animationPlayerSpec = animationPlayerSpec;
--- a/devtools/shared/specs/moz.build
+++ b/devtools/shared/specs/moz.build
@@ -1,13 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DevToolsModules(
+    'animation.js',
     'highlighters.js',
     'inspector.js',
     'storage.js',
     'styles.js',
     'stylesheets.js'
 )