diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /devtools/client/animationinspector/components/animation-details.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-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.js | 222 |
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; |