Bug 1265718 - Decouple AnimationPlayerFront from AnimationPlayerActor;r=jryans
authorEddy Bruel <ejpbruel@mozilla.com>
Tue, 24 May 2016 11:27:38 +0200
changeset 298923 e8f4f77bd99eee8e95262779c90235ce5aaaafe4
parent 298922 00f9eb3e72e805caebd204b780dc904877cab590
child 298924 3ffcd4e5783aeda3c4fa1d260634e63f40e3159a
push id77374
push usercbook@mozilla.com
push dateWed, 25 May 2016 13:20:27 +0000
treeherdermozilla-inbound@0bc5c825c58e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs1265718
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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'
 )