Bug 1406285 - Part 16: Do async rendering. r?gl draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 18 Jan 2018 13:57:21 +0900
changeset 721945 3dd820b95fab12337cce197f1de6d3df7e259dbc
parent 721944 56627ee34d762723d34373514ff4a340babc6f2c
child 721946 534acab8ae4949663ea00be93bf2c0754b956b31
push id96003
push userbmo:dakatsuka@mozilla.com
push dateThu, 18 Jan 2018 05:23:36 +0000
reviewersgl
bugs1406285
milestone59.0a1
Bug 1406285 - Part 16: Do async rendering. r?gl MozReview-Commit-ID: A1HWbkLfM5N
devtools/client/inspector/animation/animation.js
devtools/client/inspector/animation/components/AnimationItem.js
devtools/client/inspector/animation/components/AnimationList.js
devtools/client/inspector/animation/components/AnimationListContainer.js
devtools/client/inspector/animation/components/App.js
devtools/client/inspector/animation/components/graph/SummaryGraph.js
devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -17,16 +17,17 @@ const { updateElementPickerEnabled } = r
 const { updateSidebarSize } = require("./actions/sidebar");
 const { isAllAnimationEqual } = require("./utils/utils");
 
 class AnimationInspector {
   constructor(inspector, win) {
     this.inspector = inspector;
     this.win = win;
 
+    this.getAnimatedPropertyMap = this.getAnimatedPropertyMap.bind(this);
     this.getNodeFromActor = this.getNodeFromActor.bind(this);
     this.simulateAnimation = this.simulateAnimation.bind(this);
     this.toggleElementPicker = this.toggleElementPicker.bind(this);
     this.update = this.update.bind(this);
     this.onElementPickerStarted = this.onElementPickerStarted.bind(this);
     this.onElementPickerStopped = this.onElementPickerStopped.bind(this);
     this.onSidebarResized = this.onSidebarResized.bind(this);
     this.onSidebarSelect = this.onSidebarSelect.bind(this);
@@ -44,16 +45,17 @@ class AnimationInspector {
     } = this.inspector.getCommonComponentProps();
 
     const {
       onHideBoxModelHighlighter,
     } = this.inspector.getPanel("boxmodel").getComponentProps();
 
     const {
       emit: emitEventForTest,
+      getAnimatedPropertyMap,
       getNodeFromActor,
       simulateAnimation,
       toggleElementPicker,
     } = this;
 
     const target = this.inspector.target;
     this.animationsFront = new AnimationsFront(target.client, target.form);
 
@@ -61,16 +63,17 @@ class AnimationInspector {
       {
         id: "newanimationinspector",
         key: "newanimationinspector",
         store: this.inspector.store
       },
       App(
         {
           emitEventForTest,
+          getAnimatedPropertyMap,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           setSelectedNode,
           simulateAnimation,
           toggleElementPicker,
         }
       )
@@ -210,25 +213,16 @@ class AnimationInspector {
 
     const selection = this.inspector.selection;
     const animations =
       selection.isConnected() && selection.isElementNode()
       ? await this.animationsFront.getAnimationPlayersForNode(selection.nodeFront)
       : [];
 
     if (!this.animations || !isAllAnimationEqual(animations, this.animations)) {
-      await Promise.all(animations.map(animation => {
-        return new Promise(resolve => {
-          this.getAnimatedPropertyMap(animation).then(animatedPropertyMap => {
-            animation.animatedPropertyMap = animatedPropertyMap;
-            resolve();
-          });
-        });
-      }));
-
       this.inspector.store.dispatch(updateAnimations(animations));
       this.animations = animations;
     }
 
     done();
   }
 
   onElementPickerStarted() {
--- a/devtools/client/inspector/animation/components/AnimationItem.js
+++ b/devtools/client/inspector/animation/components/AnimationItem.js
@@ -11,29 +11,31 @@ const PropTypes = require("devtools/clie
 const AnimationTarget = createFactory(require("./AnimationTarget"));
 const SummaryGraph = createFactory(require("./graph/SummaryGraph"));
 
 class AnimationItem extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
+      getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const {
       animation,
       emitEventForTest,
+      getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
       simulateAnimation,
       timeScale,
     } = this.props;
 
@@ -49,16 +51,17 @@ class AnimationItem extends PureComponen
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           setSelectedNode,
         }
       ),
       SummaryGraph(
         {
           animation,
+          getAnimatedPropertyMap,
           simulateAnimation,
           timeScale,
         }
       )
     );
   }
 }
 
--- a/devtools/client/inspector/animation/components/AnimationList.js
+++ b/devtools/client/inspector/animation/components/AnimationList.js
@@ -10,29 +10,31 @@ const PropTypes = require("devtools/clie
 
 const AnimationItem = createFactory(require("./AnimationItem"));
 
 class AnimationList extends PureComponent {
   static get propTypes() {
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       emitEventForTest: PropTypes.func.isRequired,
+      getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const {
       animations,
       emitEventForTest,
+      getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
       simulateAnimation,
       timeScale,
     } = this.props;
 
@@ -40,16 +42,17 @@ class AnimationList extends PureComponen
       {
         className: "animation-list"
       },
       animations.map(animation =>
         AnimationItem(
           {
             animation,
             emitEventForTest,
+            getAnimatedPropertyMap,
             getNodeFromActor,
             onHideBoxModelHighlighter,
             onShowBoxModelHighlighterForNode,
             setSelectedNode,
             simulateAnimation,
             timeScale,
           }
         )
--- a/devtools/client/inspector/animation/components/AnimationListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimationListContainer.js
@@ -14,28 +14,30 @@ const AnimationListHeader = createFactor
 
 const TimeScale = require("../utils/timescale");
 
 class AnimationListContainer extends PureComponent {
   static get propTypes() {
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       emitEventForTest: PropTypes.func.isRequired,
+      getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
     };
   }
 
   render() {
     const {
       animations,
       emitEventForTest,
+      getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
       simulateAnimation,
     } = this.props;
     const timeScale = new TimeScale(animations);
 
@@ -47,16 +49,17 @@ class AnimationListContainer extends Pur
         {
           timeScale,
         }
       ),
       AnimationList(
         {
           animations,
           emitEventForTest,
+          getAnimatedPropertyMap,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           setSelectedNode,
           simulateAnimation,
           timeScale,
         }
       )
--- a/devtools/client/inspector/animation/components/App.js
+++ b/devtools/client/inspector/animation/components/App.js
@@ -12,16 +12,17 @@ const { connect } = require("devtools/cl
 const AnimationListContainer = createFactory(require("./AnimationListContainer"));
 const NoAnimationPanel = createFactory(require("./NoAnimationPanel"));
 
 class App extends PureComponent {
   static get propTypes() {
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       emitEventForTest: PropTypes.func.isRequired,
+      getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       toggleElementPicker: PropTypes.func.isRequired,
     };
   }
@@ -29,16 +30,17 @@ class App extends PureComponent {
   shouldComponentUpdate(nextProps, nextState) {
     return this.props.animations.length !== 0 || nextProps.animations.length !== 0;
   }
 
   render() {
     const {
       animations,
       emitEventForTest,
+      getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       setSelectedNode,
       simulateAnimation,
       toggleElementPicker,
     } = this.props;
 
@@ -46,16 +48,17 @@ class App extends PureComponent {
       {
         id: "animation-container"
       },
       animations.length ?
       AnimationListContainer(
         {
           animations,
           emitEventForTest,
+          getAnimatedPropertyMap,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           setSelectedNode,
           simulateAnimation,
         }
       )
       :
--- a/devtools/client/inspector/animation/components/graph/SummaryGraph.js
+++ b/devtools/client/inspector/animation/components/graph/SummaryGraph.js
@@ -14,16 +14,17 @@ const EndDelaySign = createFactory(requi
 const SummaryGraphPath = createFactory(require("./SummaryGraphPath"));
 
 const { getFormatStr, getStr, numberWithDecimals } = require("../../utils/l10n");
 
 class SummaryGraph extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
+      getAnimatedPropertyMap: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   getTitleText(state) {
     const getTime =
       time => getFormatStr("player.timeLabel", numberWithDecimals(time / 1000, 2));
@@ -118,29 +119,31 @@ class SummaryGraph extends PureComponent
     }
 
     return text;
   }
 
   render() {
     const {
       animation,
+      getAnimatedPropertyMap,
       simulateAnimation,
       timeScale,
     } = this.props;
 
     return dom.div(
       {
         className: "animation-summary-graph" +
                    (animation.state.isRunningOnCompositor ? " compositor" : ""),
         title: this.getTitleText(animation.state),
       },
       SummaryGraphPath(
         {
           animation,
+          getAnimatedPropertyMap,
           simulateAnimation,
           timeScale,
         }
       ),
       animation.state.delay ?
         DelaySign(
           {
             animation,
--- a/devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
+++ b/devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
@@ -17,31 +17,39 @@ const { DEFAULT_GRAPH_HEIGHT } = require
 
 // Minimum opacity for semitransparent fill color for keyframes's easing graph.
 const MIN_KEYFRAMES_EASING_OPACITY = 0.5;
 
 class SummaryGraphPath extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
+      getAnimatedPropertyMap: PropTypes.object.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
+      // Duration which can display in one pixel.
       durationPerPixel: 0,
+      // List of keyframe which consists by only offset and easing.
+      keyframesList: [],
     };
   }
 
   componentDidMount() {
-    this.updateDurationPerPixel();
+    this.updateState(this.props.animation);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    this.updateState(nextProps.animation);
   }
 
   /**
    * Return animatable keyframes list which has only offset and easing.
    * Also, this method remove duplicate keyframes.
    * For example, if the given animatedPropertyMap is,
    * [
    *   {
@@ -127,46 +135,47 @@ class SummaryGraphPath extends PureCompo
           keyframe1.easing !== keyframe2.easing) {
         return false;
       }
     }
 
     return true;
   }
 
-  updateDurationPerPixel() {
+  async updateState(animation) {
     const {
-      animation,
+      getAnimatedPropertyMap,
       timeScale,
     } = this.props;
 
+    const animatedPropertyMap = await getAnimatedPropertyMap(animation);
+    const keyframesList = this.getOffsetAndEasingOnlyKeyframes(animatedPropertyMap);
+
     const thisEl = ReactDOM.findDOMNode(this);
     const totalDuration = this.getTotalDuration(animation, timeScale);
     const durationPerPixel = totalDuration / thisEl.parentNode.clientWidth;
 
-    this.setState({ durationPerPixel });
+    this.setState({ durationPerPixel, keyframesList });
   }
 
   render() {
-    const { durationPerPixel } = this.state;
+    const { durationPerPixel, keyframesList } = this.state;
 
     if (!durationPerPixel) {
       return dom.svg();
     }
 
     const {
       animation,
       simulateAnimation,
       timeScale,
     } = this.props;
 
     const totalDuration = this.getTotalDuration(animation, timeScale);
     const startTime = timeScale.minStartTime;
-    const keyframesList =
-      this.getOffsetAndEasingOnlyKeyframes(animation.animatedPropertyMap);
     const opacity = Math.max(1 / keyframesList.length, MIN_KEYFRAMES_EASING_OPACITY);
 
     return dom.svg(
       {
         className: "animation-summary-graph-path",
         preserveAspectRatio: "none",
         viewBox: `${ startTime } -${ DEFAULT_GRAPH_HEIGHT } `
                  + `${ totalDuration } ${ DEFAULT_GRAPH_HEIGHT }`,