summaryrefslogtreecommitdiffstats
path: root/devtools/client/animationinspector/components/animation-details.js
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /devtools/client/animationinspector/components/animation-details.js
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/animationinspector/components/animation-details.js')
-rw-r--r--devtools/client/animationinspector/components/animation-details.js222
1 files changed, 222 insertions, 0 deletions
diff --git a/devtools/client/animationinspector/components/animation-details.js b/devtools/client/animationinspector/components/animation-details.js
new file mode 100644
index 000000000..c042ccac0
--- /dev/null
+++ b/devtools/client/animationinspector/components/animation-details.js
@@ -0,0 +1,222 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* 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 {Task} = require("devtools/shared/task");
+const EventEmitter = require("devtools/shared/event-emitter");
+const {createNode, TimeScale} = require("devtools/client/animationinspector/utils");
+const {Keyframes} = require("devtools/client/animationinspector/components/keyframes");
+
+/**
+ * UI component responsible for displaying detailed information for a given
+ * animation.
+ * This includes information about timing, easing, keyframes, animated
+ * properties.
+ *
+ * @param {Object} serverTraits The list of server-side capabilities.
+ */
+function AnimationDetails(serverTraits) {
+ EventEmitter.decorate(this);
+
+ this.onFrameSelected = this.onFrameSelected.bind(this);
+
+ this.keyframeComponents = [];
+ this.serverTraits = serverTraits;
+}
+
+exports.AnimationDetails = AnimationDetails;
+
+AnimationDetails.prototype = {
+ // These are part of frame objects but are not animated properties. This
+ // array is used to skip them.
+ NON_PROPERTIES: ["easing", "composite", "computedOffset", "offset"],
+
+ init: function (containerEl) {
+ this.containerEl = containerEl;
+ },
+
+ destroy: function () {
+ this.unrender();
+ this.containerEl = null;
+ this.serverTraits = null;
+ },
+
+ unrender: function () {
+ for (let component of this.keyframeComponents) {
+ component.off("frame-selected", this.onFrameSelected);
+ component.destroy();
+ }
+ this.keyframeComponents = [];
+
+ while (this.containerEl.firstChild) {
+ this.containerEl.firstChild.remove();
+ }
+ },
+
+ getPerfDataForProperty: function (animation, propertyName) {
+ let warning = "";
+ let className = "";
+ if (animation.state.propertyState) {
+ let isRunningOnCompositor;
+ for (let propState of animation.state.propertyState) {
+ if (propState.property == propertyName) {
+ isRunningOnCompositor = propState.runningOnCompositor;
+ if (typeof propState.warning != "undefined") {
+ warning = propState.warning;
+ }
+ break;
+ }
+ }
+ if (isRunningOnCompositor && warning == "") {
+ className = "oncompositor";
+ } else if (!isRunningOnCompositor && warning != "") {
+ className = "warning";
+ }
+ }
+ return {className, warning};
+ },
+
+ /**
+ * Get a list of the tracks of the animation actor
+ * @return {Object} A list of tracks, one per animated property, each
+ * with a list of keyframes
+ */
+ getTracks: Task.async(function* () {
+ let tracks = {};
+
+ /*
+ * getFrames is a AnimationPlayorActor method that returns data about the
+ * keyframes of the animation.
+ * In FF48, the data it returns change, and will hold only longhand
+ * properties ( e.g. borderLeftWidth ), which does not match what we
+ * want to display in the animation detail.
+ * A new AnimationPlayerActor function, getProperties, is introduced,
+ * that returns the animated css properties of the animation and their
+ * keyframes values.
+ * If the animation actor has the getProperties function, we use it, and if
+ * not, we fall back to getFrames, which then returns values we used to
+ * handle.
+ */
+ if (this.serverTraits.hasGetProperties) {
+ let properties = yield this.animation.getProperties();
+ for (let {name, values} of properties) {
+ if (!tracks[name]) {
+ tracks[name] = [];
+ }
+
+ for (let {value, offset} of values) {
+ tracks[name].push({value, offset});
+ }
+ }
+ } else {
+ let frames = yield this.animation.getFrames();
+ for (let frame of frames) {
+ for (let name in frame) {
+ if (this.NON_PROPERTIES.indexOf(name) != -1) {
+ continue;
+ }
+
+ if (!tracks[name]) {
+ tracks[name] = [];
+ }
+
+ tracks[name].push({
+ value: frame[name],
+ offset: frame.computedOffset
+ });
+ }
+ }
+ }
+
+ return tracks;
+ }),
+
+ render: Task.async(function* (animation) {
+ this.unrender();
+
+ if (!animation) {
+ return;
+ }
+ this.animation = animation;
+
+ // We might have been destroyed in the meantime, or the component might
+ // have been re-rendered.
+ if (!this.containerEl || this.animation !== animation) {
+ return;
+ }
+
+ // Build an element for each animated property track.
+ this.tracks = yield this.getTracks(animation, this.serverTraits);
+
+ // Useful for tests to know when the keyframes have been retrieved.
+ this.emit("keyframes-retrieved");
+
+ for (let propertyName in this.tracks) {
+ let line = createNode({
+ parent: this.containerEl,
+ attributes: {"class": "property"}
+ });
+ let {warning, className} =
+ this.getPerfDataForProperty(animation, propertyName);
+ createNode({
+ // text-overflow doesn't work in flex items, so we need a second level
+ // of container to actually have an ellipsis on the name.
+ // See bug 972664.
+ parent: createNode({
+ parent: line,
+ attributes: {"class": "name"}
+ }),
+ textContent: getCssPropertyName(propertyName),
+ attributes: {"title": warning,
+ "class": className}
+ });
+
+ // Add the keyframes diagram for this property.
+ let framesWrapperEl = createNode({
+ parent: line,
+ attributes: {"class": "track-container"}
+ });
+
+ let framesEl = createNode({
+ parent: framesWrapperEl,
+ attributes: {"class": "frames"}
+ });
+
+ // Scale the list of keyframes according to the current time scale.
+ let {x, w} = TimeScale.getAnimationDimensions(animation);
+ framesEl.style.left = `${x}%`;
+ framesEl.style.width = `${w}%`;
+
+ let keyframesComponent = new Keyframes();
+ keyframesComponent.init(framesEl);
+ keyframesComponent.render({
+ keyframes: this.tracks[propertyName],
+ propertyName: propertyName,
+ animation: animation
+ });
+ keyframesComponent.on("frame-selected", this.onFrameSelected);
+
+ this.keyframeComponents.push(keyframesComponent);
+ }
+ }),
+
+ onFrameSelected: function (e, args) {
+ // Relay the event up, it's needed in parents too.
+ this.emit(e, args);
+ }
+};
+
+/**
+ * Turn propertyName into property-name.
+ * @param {String} jsPropertyName A camelcased CSS property name. Typically
+ * something that comes out of computed styles. E.g. borderBottomColor
+ * @return {String} The corresponding CSS property name: border-bottom-color
+ */
+function getCssPropertyName(jsPropertyName) {
+ return jsPropertyName.replace(/[A-Z]/g, "-$&").toLowerCase();
+}
+exports.getCssPropertyName = getCssPropertyName;