Commit 6ee0600d authored by samli@chromium.org's avatar samli@chromium.org

Devtools Animations: Display keyframes for CSS Animations in inspector

This change displays CSS animation keyframes alongside the associated
animation player in the Animations sidebar pane. No visible changes are
introduced except with the hidden 'Animation Inspection' experiment enabled.

BUG=419269

Review URL: https://codereview.chromium.org/664993002

git-svn-id: svn://svn.chromium.org/blink/trunk@184328 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 8765f3f1
...@@ -218,6 +218,15 @@ CSSAnimations::CSSAnimations() ...@@ -218,6 +218,15 @@ CSSAnimations::CSSAnimations()
{ {
} }
const AtomicString CSSAnimations::getAnimationNameForInspector(const AnimationPlayer& player)
{
for (const auto& it : m_animations) {
if (it.value->sequenceNumber() == player.sequenceNumber())
return it.key;
}
return nullAtom;
}
PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(const Element* animatingElement, Element& element, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver) PassOwnPtrWillBeRawPtr<CSSAnimationUpdate> CSSAnimations::calculateUpdate(const Element* animatingElement, Element& element, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
{ {
OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = adoptPtrWillBeNoop(new CSSAnimationUpdate()); OwnPtrWillBeRawPtr<CSSAnimationUpdate> update = adoptPtrWillBeNoop(new CSSAnimationUpdate());
......
...@@ -167,6 +167,8 @@ class CSSAnimations final { ...@@ -167,6 +167,8 @@ class CSSAnimations final {
public: public:
CSSAnimations(); CSSAnimations();
const AtomicString getAnimationNameForInspector(const AnimationPlayer&);
// FIXME: This method is only used here and in the legacy animations // FIXME: This method is only used here and in the legacy animations
// implementation. It should be made private or file-scope when the legacy // implementation. It should be made private or file-scope when the legacy
// engine is removed. // engine is removed.
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
#include "core/animation/AnimationNode.h" #include "core/animation/AnimationNode.h"
#include "core/animation/AnimationPlayer.h" #include "core/animation/AnimationPlayer.h"
#include "core/animation/ElementAnimation.h" #include "core/animation/ElementAnimation.h"
#include "core/css/CSSKeyframeRule.h"
#include "core/css/CSSKeyframesRule.h"
#include "core/inspector/InspectorDOMAgent.h" #include "core/inspector/InspectorDOMAgent.h"
#include "core/inspector/InspectorStyleSheet.h"
namespace blink { namespace blink {
...@@ -35,6 +38,77 @@ void InspectorAnimationAgent::reset() ...@@ -35,6 +38,77 @@ void InspectorAnimationAgent::reset()
m_idToAnimationPlayer.clear(); m_idToAnimationPlayer.clear();
} }
static PassRefPtr<TypeBuilder::Animation::AnimationNode> buildObjectForAnimationNode(AnimationNode* animationNode)
{
RefPtr<TypeBuilder::Animation::AnimationNode> animationObject = TypeBuilder::Animation::AnimationNode::create()
.setStartDelay(animationNode->specifiedTiming().startDelay)
.setPlaybackRate(animationNode->specifiedTiming().playbackRate)
.setIterationStart(animationNode->specifiedTiming().iterationStart)
.setIterationCount(animationNode->specifiedTiming().iterationCount)
.setDuration(animationNode->duration())
.setDirection(animationNode->specifiedTiming().direction)
.setFillMode(animationNode->specifiedTiming().fillMode)
.setTimeFraction(animationNode->timeFraction())
.setName(animationNode->name());
return animationObject.release();
}
static String playerId(AnimationPlayer& player)
{
return String::number(player.sequenceNumber());
}
static PassRefPtr<TypeBuilder::Animation::AnimationPlayer> buildObjectForAnimationPlayer(AnimationPlayer& animationPlayer, PassRefPtr<TypeBuilder::Animation::KeyframesRule> keyframeRule = nullptr)
{
RefPtr<TypeBuilder::Animation::AnimationNode> animationObject = buildObjectForAnimationNode(animationPlayer.source());
if (keyframeRule)
animationObject->setKeyframesRule(keyframeRule);
RefPtr<TypeBuilder::Animation::AnimationPlayer> playerObject = TypeBuilder::Animation::AnimationPlayer::create()
.setId(playerId(animationPlayer))
.setPausedState(animationPlayer.paused())
.setPlayState(animationPlayer.playState())
.setPlaybackRate(animationPlayer.playbackRate())
.setStartTime(animationPlayer.startTime())
.setCurrentTime(animationPlayer.currentTime())
.setSource(animationObject.release());
return playerObject.release();
}
static PassRefPtr<TypeBuilder::Animation::KeyframeStyle> buildObjectForStyleKeyframe(StyleKeyframe* keyframe)
{
RefPtrWillBeRawPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), keyframe->mutableProperties().ensureCSSStyleDeclaration(), 0);
RefPtr<TypeBuilder::Animation::KeyframeStyle> keyframeObject = TypeBuilder::Animation::KeyframeStyle::create()
.setOffset(keyframe->keyText())
.setStyle(inspectorStyle->buildObjectForStyle());
return keyframeObject.release();
}
static PassRefPtr<TypeBuilder::Animation::KeyframesRule> buildObjectForStyleRuleKeyframes(const StyleRuleKeyframes* keyframesRule)
{
RefPtr<TypeBuilder::Array<TypeBuilder::Animation::KeyframeStyle> > keyframes = TypeBuilder::Array<TypeBuilder::Animation::KeyframeStyle>::create();
const WillBeHeapVector<RefPtrWillBeMember<StyleKeyframe> >& styleKeyframes = keyframesRule->keyframes();
for (const auto& styleKeyframe : styleKeyframes)
keyframes->addItem(buildObjectForStyleKeyframe(styleKeyframe.get()));
RefPtr<TypeBuilder::Animation::KeyframesRule> keyframesObject = TypeBuilder::Animation::KeyframesRule::create()
.setKeyframes(keyframes);
keyframesObject->setName(keyframesRule->name());
return keyframesObject.release();
}
static PassRefPtr<TypeBuilder::Animation::KeyframesRule> buildObjectForKeyframesRule(const Element& element, const AnimationPlayer& player)
{
StyleResolver& styleResolver = element.ownerDocument()->ensureStyleResolver();
// FIXME: Add support for web anim
CSSAnimations& cssAnimations = element.activeAnimations()->cssAnimations();
const AtomicString animationName = cssAnimations.getAnimationNameForInspector(player);
ASSERT(animationName);
const StyleRuleKeyframes* keyframes = cssAnimations.matchScopedKeyframesRule(&styleResolver, &element, animationName.impl());
return buildObjectForStyleRuleKeyframes(keyframes);
}
void InspectorAnimationAgent::getAnimationPlayersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer> >& animationPlayersArray) void InspectorAnimationAgent::getAnimationPlayersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer> >& animationPlayersArray)
{ {
animationPlayersArray = TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer>::create(); animationPlayersArray = TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer>::create();
...@@ -46,7 +120,14 @@ void InspectorAnimationAgent::getAnimationPlayersForNode(ErrorString* errorStrin ...@@ -46,7 +120,14 @@ void InspectorAnimationAgent::getAnimationPlayersForNode(ErrorString* errorStrin
for (WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer> >::iterator it = players.begin(); it != players.end(); ++it) { for (WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer> >::iterator it = players.begin(); it != players.end(); ++it) {
AnimationPlayer& player = *(it->get()); AnimationPlayer& player = *(it->get());
m_idToAnimationPlayer.set(playerId(player), &player); m_idToAnimationPlayer.set(playerId(player), &player);
RefPtr<TypeBuilder::Animation::AnimationPlayer> animationPlayerObject = buildObjectForAnimationPlayer(player); RefPtr<TypeBuilder::Animation::AnimationPlayer> animationPlayerObject;
// FIXME: Add support for web animations
if (!element->activeAnimations()->cssAnimations().getAnimationNameForInspector(player).isNull()) {
RefPtr<TypeBuilder::Animation::KeyframesRule> keyframeRule = buildObjectForKeyframesRule(*element, player);
animationPlayerObject = buildObjectForAnimationPlayer(player, keyframeRule.release());
} else {
animationPlayerObject = buildObjectForAnimationPlayer(player);
}
animationPlayersArray->addItem(animationPlayerObject); animationPlayersArray->addItem(animationPlayerObject);
} }
} }
...@@ -97,39 +178,6 @@ AnimationPlayer* InspectorAnimationAgent::assertAnimationPlayer(ErrorString* err ...@@ -97,39 +178,6 @@ AnimationPlayer* InspectorAnimationAgent::assertAnimationPlayer(ErrorString* err
return player; return player;
} }
String InspectorAnimationAgent::playerId(AnimationPlayer& player)
{
return String::number(player.sequenceNumber());
}
PassRefPtr<TypeBuilder::Animation::AnimationPlayer> InspectorAnimationAgent::buildObjectForAnimationPlayer(AnimationPlayer& animationPlayer)
{
RefPtr<TypeBuilder::Animation::AnimationPlayer> playerObject = TypeBuilder::Animation::AnimationPlayer::create()
.setId(playerId(animationPlayer))
.setPausedState(animationPlayer.paused())
.setPlayState(animationPlayer.playState())
.setPlaybackRate(animationPlayer.playbackRate())
.setStartTime(animationPlayer.startTime())
.setCurrentTime(animationPlayer.currentTime())
.setSource(buildObjectForAnimationNode(*(animationPlayer.source())));
return playerObject.release();
}
PassRefPtr<TypeBuilder::Animation::AnimationNode> InspectorAnimationAgent::buildObjectForAnimationNode(AnimationNode& animationNode)
{
RefPtr<TypeBuilder::Animation::AnimationNode> animationObject = TypeBuilder::Animation::AnimationNode::create()
.setStartDelay(animationNode.specifiedTiming().startDelay)
.setPlaybackRate(animationNode.specifiedTiming().playbackRate)
.setIterationStart(animationNode.specifiedTiming().iterationStart)
.setIterationCount(animationNode.specifiedTiming().iterationCount)
.setDuration(animationNode.duration())
.setDirection(animationNode.specifiedTiming().direction)
.setFillMode(animationNode.specifiedTiming().fillMode)
.setTimeFraction(animationNode.timeFraction())
.setName(animationNode.name());
return animationObject.release();
}
void InspectorAnimationAgent::trace(Visitor* visitor) void InspectorAnimationAgent::trace(Visitor* visitor)
{ {
#if ENABLE(OILPAN) #if ENABLE(OILPAN)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define InspectorAnimationAgent_h #define InspectorAnimationAgent_h
#include "core/InspectorFrontend.h" #include "core/InspectorFrontend.h"
#include "core/css/CSSKeyframesRule.h"
#include "core/inspector/InspectorBaseAgent.h" #include "core/inspector/InspectorBaseAgent.h"
#include "wtf/PassOwnPtr.h" #include "wtf/PassOwnPtr.h"
#include "wtf/text/WTFString.h" #include "wtf/text/WTFString.h"
...@@ -14,6 +15,7 @@ namespace blink { ...@@ -14,6 +15,7 @@ namespace blink {
class AnimationNode; class AnimationNode;
class AnimationPlayer; class AnimationPlayer;
class Element;
class InspectorDOMAgent; class InspectorDOMAgent;
class InspectorAnimationAgent final : public InspectorBaseAgent<InspectorAnimationAgent>, public InspectorBackendDispatcher::AnimationCommandHandler { class InspectorAnimationAgent final : public InspectorBaseAgent<InspectorAnimationAgent>, public InspectorBackendDispatcher::AnimationCommandHandler {
...@@ -44,11 +46,6 @@ public: ...@@ -44,11 +46,6 @@ public:
private: private:
InspectorAnimationAgent(InspectorDOMAgent*); InspectorAnimationAgent(InspectorDOMAgent*);
String playerId(AnimationPlayer&);
PassRefPtr<TypeBuilder::Animation::AnimationPlayer> buildObjectForAnimationPlayer(AnimationPlayer&);
PassRefPtr<TypeBuilder::Animation::AnimationNode> buildObjectForAnimationNode(AnimationNode&);
RawPtrWillBeMember<InspectorDOMAgent> m_domAgent; RawPtrWillBeMember<InspectorDOMAgent> m_domAgent;
InspectorFrontend::Animation* m_frontend; InspectorFrontend::Animation* m_frontend;
WillBeHeapHashMap<String, RefPtrWillBeMember<AnimationPlayer> > m_idToAnimationPlayer; WillBeHeapHashMap<String, RefPtrWillBeMember<AnimationPlayer> > m_idToAnimationPlayer;
......
...@@ -44,9 +44,22 @@ WebInspector.AnimationsSidebarPane.prototype = { ...@@ -44,9 +44,22 @@ WebInspector.AnimationsSidebarPane.prototype = {
var id = player.source().name() ? player.source().name() : player.id(); var id = player.source().name() ? player.source().name() : player.id();
separatorElement.createTextChild(WebInspector.UIString("Animation") + " " + id); separatorElement.createTextChild(WebInspector.UIString("Animation") + " " + id);
this.bodyElement.appendChild(this._animationSections[i].element); this.bodyElement.appendChild(this._animationSections[i].element);
if (player.source().keyframesRule()) {
var keyframes = player.source().keyframesRule().keyframes();
for (var j = 0; j < keyframes.length; j++) {
var inlineStyle = { selectorText: keyframes[j].offset(), style: keyframes[j].style(), isAttribute: true };
var section = new WebInspector.StylePropertiesSection(this._stylesPane, inlineStyle, true, false);
section.expanded = true;
this.bodyElement.appendChild(section.element);
}
}
} }
} }
if (!node)
return;
if (this._selectedNode === node) { if (this._selectedNode === node) {
for (var i = 0; i < this._animationSections.length; ++i) for (var i = 0; i < this._animationSections.length; ++i)
this._animationSections[i].updateCurrentTime(); this._animationSections[i].updateCurrentTime();
......
...@@ -183,6 +183,8 @@ WebInspector.AnimationModel.AnimationNode = function(target, payload) ...@@ -183,6 +183,8 @@ WebInspector.AnimationModel.AnimationNode = function(target, payload)
{ {
WebInspector.SDKObject.call(this, target); WebInspector.SDKObject.call(this, target);
this._payload = payload; this._payload = payload;
if (payload.keyframesRule)
this._keyframesRule = new WebInspector.AnimationModel.KeyframesRule(target, payload.keyframesRule);
} }
WebInspector.AnimationModel.AnimationNode.prototype = { WebInspector.AnimationModel.AnimationNode.prototype = {
...@@ -258,5 +260,91 @@ WebInspector.AnimationModel.AnimationNode.prototype = { ...@@ -258,5 +260,91 @@ WebInspector.AnimationModel.AnimationNode.prototype = {
return this._payload.name; return this._payload.name;
}, },
/**
* @return {?WebInspector.AnimationModel.KeyframesRule}
*/
keyframesRule: function()
{
return this._keyframesRule;
},
__proto__: WebInspector.SDKObject.prototype
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!WebInspector.Target} target
* @param {!AnimationAgent.KeyframesRule} payload
*/
WebInspector.AnimationModel.KeyframesRule = function(target, payload)
{
WebInspector.SDKObject.call(this, target);
this._payload = payload;
this._keyframes = this._payload.keyframes.map(function (keyframeStyle) {
return new WebInspector.AnimationModel.KeyframeStyle(target, keyframeStyle);
});
}
WebInspector.AnimationModel.KeyframesRule.prototype = {
/**
* @param {!Array.<!AnimationAgent.KeyframeStyle>} payload
*/
_setKeyframesPayload: function(payload)
{
this._keyframes = payload.map(function (keyframeStyle) {
return new WebInspector.AnimationModel.KeyframeStyle(this._target, keyframeStyle);
});
},
/**
* @return {string|undefined}
*/
name: function()
{
return this._payload.name;
},
/**
* @return {!Array.<!WebInspector.AnimationModel.KeyframeStyle>}
*/
keyframes: function()
{
return this._keyframes;
},
__proto__: WebInspector.SDKObject.prototype
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!WebInspector.Target} target
* @param {!AnimationAgent.KeyframeStyle} payload
*/
WebInspector.AnimationModel.KeyframeStyle = function(target, payload)
{
WebInspector.SDKObject.call(this, target);
this._payload = payload;
this._style = WebInspector.CSSStyleDeclaration.parsePayload(this.target().cssModel, payload.style);
}
WebInspector.AnimationModel.KeyframeStyle.prototype = {
/**
* @return {string}
*/
offset: function()
{
return this._payload.offset;
},
/**
* @return {!WebInspector.CSSStyleDeclaration}
*/
style: function()
{
return this._style;
},
__proto__: WebInspector.SDKObject.prototype __proto__: WebInspector.SDKObject.prototype
} }
\ No newline at end of file
...@@ -4452,9 +4452,28 @@ ...@@ -4452,9 +4452,28 @@
{ "name": "direction", "type": "number", "description": "<code>AnimationNode</code>'s playback direction." }, { "name": "direction", "type": "number", "description": "<code>AnimationNode</code>'s playback direction." },
{ "name": "fillMode", "type": "number", "description": "<code>AnimationNode</code>'s fill mode." }, { "name": "fillMode", "type": "number", "description": "<code>AnimationNode</code>'s fill mode." },
{ "name": "timeFraction", "type": "number", "description": "<code>AnimationNode</code>'s time fraction." }, { "name": "timeFraction", "type": "number", "description": "<code>AnimationNode</code>'s time fraction." },
{ "name": "name", "type": "string", "description": "<code>AnimationNode</code> name."} { "name": "name", "type": "string", "description": "<code>AnimationNode</code>'s name." },
{ "name": "keyframesRule", "$ref": "KeyframesRule", "optional": true, "description": "<code>AnimationNode</code>'s keyframes." }
], ],
"description": "AnimationNode instance" "description": "AnimationNode instance"
},
{
"id": "KeyframesRule",
"type": "object",
"properties": [
{ "name": "name", "type": "string", "optional": true, "description": "CSS keyframed animation's name." },
{ "name": "keyframes", "type": "array", "items": { "$ref": "KeyframeStyle" }, "description": "List of animation keyframes." }
],
"description": "Keyframes Rule"
},
{
"id": "KeyframeStyle",
"type": "object",
"properties": [
{ "name": "offset", "type": "string", "description": "Keyframe's time offset." },
{ "name": "style", "$ref": "CSS.CSSStyle", "description": "Keyframe's associated CSS style declaration." }
],
"description": "Keyframe Style"
} }
], ],
"commands": [ "commands": [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment