Bug 1406285 - Part 10: Implement negative delay path. r=gl
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Thu, 18 Jan 2018 13:02:10 +0900
changeset 454266 101599271efd0035d479689e82988cfe73257c86
parent 454265 d948ac6aff2cbfdffaa0dcfb1fbe4c3eaf6a6ac2
child 454267 479b3feae1c579c073abefe29855876830fe2503
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgl
bugs1406285
milestone59.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 1406285 - Part 10: Implement negative delay path. r=gl MozReview-Commit-ID: 4bje1aOBHth
devtools/client/inspector/animation/components/graph/NegativeDelayPath.js
devtools/client/inspector/animation/components/graph/NegativePath.js
devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
devtools/client/inspector/animation/components/graph/moz.build
devtools/client/themes/animation.css
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/graph/NegativeDelayPath.js
@@ -0,0 +1,41 @@
+/* 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 PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const NegativePath = require("./NegativePath");
+
+class NegativeDelayPath extends NegativePath {
+  static get propTypes() {
+    return {
+      animation: PropTypes.object.isRequired,
+      durationPerPixel: PropTypes.number.isRequired,
+      keyframes: PropTypes.object.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
+      totalDuration: PropTypes.number.isRequired,
+    };
+  }
+
+  constructor(props) {
+    props.className = "animation-negative-delay-path";
+    super(props);
+  }
+
+  renderGraph(state, helper) {
+    const startTime = state.delay;
+    const endTime = 0;
+    const segments = helper.createPathSegments(startTime, endTime);
+
+    return dom.path(
+      {
+        d: helper.toPathString(segments),
+      }
+    );
+  }
+}
+
+module.exports = NegativeDelayPath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/graph/NegativePath.js
@@ -0,0 +1,90 @@
+/* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const { SummaryGraphHelper, toPathString } = require("../../utils/graph-helper");
+
+class NegativePath extends PureComponent {
+  static get propTypes() {
+    return {
+      animation: PropTypes.object.isRequired,
+      className: PropTypes.string.isRequired,
+      durationPerPixel: PropTypes.number.isRequired,
+      keyframes: PropTypes.object.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
+      totalDuration: PropTypes.number.isRequired,
+    };
+  }
+
+  render() {
+    const {
+      animation,
+      className,
+      durationPerPixel,
+      keyframes,
+      simulateAnimation,
+      totalDuration,
+    } = this.props;
+
+    const { state } = animation;
+    const effectTiming = Object.assign({}, state, {
+      fill: "both",
+      iterations: state.iterationCount ? state.iterationCount : Infinity
+    });
+
+    // Create new keyframes for opacity as computed style.
+    // The reason why we use computed value instead of computed timing progress is to
+    // include the easing in keyframes as well. Although the computed timing progress
+    // is not affected by the easing in keyframes at all, computed value reflects that.
+    const frames = keyframes.map(keyframe => {
+      return {
+        opacity: keyframe.offset,
+        offset: keyframe.offset,
+        easing: keyframe.easing
+      };
+    });
+
+    const simulatedAnimation = simulateAnimation(frames, effectTiming, true);
+    const simulatedElement = simulatedAnimation.effect.target;
+    const win = simulatedElement.ownerGlobal;
+
+    // Set the underlying opacity to zero so that if we sample the animation's output
+    // during the delay phase and it is not filling backwards, we get zero.
+    simulatedElement.style.opacity = 0;
+
+    const getValueFunc = time => {
+      simulatedAnimation.currentTime = time;
+      return win.getComputedStyle(simulatedElement).opacity;
+    };
+
+    const toPathStringFunc = segments => {
+      const firstSegment = segments[0];
+      let pathString = `M${ firstSegment.x },0 `;
+      pathString += toPathString(segments);
+      const lastSegment = segments[segments.length - 1];
+      pathString += `L${ lastSegment.x },0 Z`;
+      return pathString;
+    };
+
+    const helper = new SummaryGraphHelper(state, keyframes,
+                                          totalDuration, durationPerPixel,
+                                          getValueFunc, toPathStringFunc);
+    const offset = state.previousStartTime ? state.previousStartTime : 0;
+
+    return dom.g(
+      {
+        className,
+        transform: `translate(${ offset })`
+      },
+      this.renderGraph(state, helper)
+    );
+  }
+}
+
+module.exports = NegativePath;
--- a/devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
+++ b/devtools/client/inspector/animation/components/graph/SummaryGraphPath.js
@@ -6,16 +6,17 @@
 
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 
 const ComputedTimingPath = createFactory(require("./ComputedTimingPath"));
 const EffectTimingPath = createFactory(require("./EffectTimingPath"));
+const NegativeDelayPath = createFactory(require("./NegativeDelayPath"));
 const { DEFAULT_GRAPH_HEIGHT } = require("../../utils/graph-helper");
 
 // 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 {
@@ -177,23 +178,37 @@ class SummaryGraphPath extends PureCompo
             keyframes,
             opacity,
             simulateAnimation,
             totalDuration,
           }
         )
       ),
       animation.state.easing !== "linear" ?
-      EffectTimingPath(
-        {
-          animation,
-          durationPerPixel,
-          simulateAnimation,
-          totalDuration,
-        }
-      )
+        EffectTimingPath(
+          {
+            animation,
+            durationPerPixel,
+            simulateAnimation,
+            totalDuration,
+          }
+        )
+      :
+      null,
+      animation.state.delay < 0 ?
+        keyframesList.map(keyframes => {
+          return NegativeDelayPath(
+            {
+              animation,
+              durationPerPixel,
+              keyframes,
+              simulateAnimation,
+              totalDuration,
+            }
+          );
+        })
       :
       null
     );
   }
 }
 
 module.exports = SummaryGraphPath;
--- a/devtools/client/inspector/animation/components/graph/moz.build
+++ b/devtools/client/inspector/animation/components/graph/moz.build
@@ -2,12 +2,14 @@
 # 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(
     'ComputedTimingPath.js',
     'DelaySign.js',
     'EffectTimingPath.js',
     'EndDelaySign.js',
+    'NegativeDelayPath.js',
+    'NegativePath.js',
     'SummaryGraph.js',
     'SummaryGraphPath.js',
     'TimingPath.js'
 )
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -114,16 +114,24 @@
   transform: scale(1, -1);
   vector-effect: non-scaling-stroke;
 }
 
 .animation-effect-timing-path path.infinity:nth-child(n+2) {
   opacity: 0.3;
 }
 
+.animation-negative-delay-path path {
+  fill: none;
+  stroke: var(--theme-graphs-grey);
+  stroke-dasharray: 2px 2px;
+  transform: scale(1, -1);
+  vector-effect: non-scaling-stroke;
+}
+
 .animation-delay-sign,
 .animation-end-delay-sign {
   background-color: var(--theme-graphs-grey);
   height: 3px;
   position: absolute;
   top: calc(100% - 1.5px);
 }