Commit 403adb97 authored by samli@chromium.org's avatar samli@chromium.org

Devtools Animations: Basic animation inspection & control in Styles pane

Add a new hidden devtools experiment for animation inspection within the
inspector. A new inspector domain is created for Animations.

CSS Animations, CSS Transitions and Web Animations can be viewed in an
Animations pane when an animation is in effect and targeting the element
being viewed in the Elements pane. Each animation can be paused, played
and scrubbed based on time position. Animation properties are shown for
all animations.

BUG=419269

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

git-svn-id: svn://svn.chromium.org/blink/trunk@183847 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 7c8b77b7
......@@ -1258,6 +1258,8 @@
'inspector/InjectedScriptManager.h',
'inspector/InjectedScriptModule.cpp',
'inspector/InjectedScriptModule.h',
'inspector/InspectorAnimationAgent.cpp',
'inspector/InspectorAnimationAgent.h',
'inspector/InspectorApplicationCacheAgent.cpp',
'inspector/InspectorApplicationCacheAgent.h',
'inspector/InspectorBaseAgent.cpp',
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/inspector/InspectorAnimationAgent.h"
#include "core/animation/AnimationNode.h"
#include "core/animation/AnimationPlayer.h"
#include "core/animation/ElementAnimation.h"
#include "core/inspector/InspectorDOMAgent.h"
namespace blink {
InspectorAnimationAgent::InspectorAnimationAgent(InspectorDOMAgent* domAgent)
: InspectorBaseAgent<InspectorAnimationAgent>("Animation")
, m_domAgent(domAgent)
, m_frontend(0)
{
}
void InspectorAnimationAgent::setFrontend(InspectorFrontend* frontend)
{
m_frontend = frontend->animation();
}
void InspectorAnimationAgent::clearFrontend()
{
m_frontend = nullptr;
}
void InspectorAnimationAgent::reset()
{
m_idToAnimationPlayer.clear();
}
void InspectorAnimationAgent::getAnimationPlayersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer> >& animationPlayersArray)
{
animationPlayersArray = TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer>::create();
Element* element = m_domAgent->assertElement(errorString, nodeId);
if (!element)
return;
m_idToAnimationPlayer.clear();
WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer> > players = ElementAnimation::getAnimationPlayers(*element);
for (WillBeHeapVector<RefPtrWillBeMember<AnimationPlayer> >::iterator it = players.begin(); it != players.end(); ++it) {
AnimationPlayer& player = *(it->get());
m_idToAnimationPlayer.set(playerId(player), &player);
RefPtr<TypeBuilder::Animation::AnimationPlayer> animationPlayerObject = buildObjectForAnimationPlayer(player);
animationPlayersArray->addItem(animationPlayerObject);
}
}
void InspectorAnimationAgent::pauseAnimationPlayer(ErrorString* errorString, const String& id, RefPtr<TypeBuilder::Animation::AnimationPlayer>& animationPlayer)
{
AnimationPlayer* player = assertAnimationPlayer(errorString, id);
if (!player)
return;
player->pause();
animationPlayer = buildObjectForAnimationPlayer(*player);
}
void InspectorAnimationAgent::playAnimationPlayer(ErrorString* errorString, const String& id, RefPtr<TypeBuilder::Animation::AnimationPlayer>& animationPlayer)
{
AnimationPlayer* player = assertAnimationPlayer(errorString, id);
if (!player)
return;
player->play();
animationPlayer = buildObjectForAnimationPlayer(*player);
}
void InspectorAnimationAgent::setAnimationPlayerCurrentTime(ErrorString* errorString, const String& id, double currentTime, RefPtr<TypeBuilder::Animation::AnimationPlayer>& animationPlayer)
{
AnimationPlayer* player = assertAnimationPlayer(errorString, id);
if (!player)
return;
player->setCurrentTime(currentTime);
animationPlayer = buildObjectForAnimationPlayer(*player);
}
void InspectorAnimationAgent::getAnimationPlayerState(ErrorString* errorString, const String& id, double* currentTime, bool* isRunning)
{
AnimationPlayer* player = assertAnimationPlayer(errorString, id);
if (!player)
return;
*currentTime = player->currentTime();
*isRunning = player->playing();
}
AnimationPlayer* InspectorAnimationAgent::assertAnimationPlayer(ErrorString* errorString, const String& id)
{
AnimationPlayer* player = m_idToAnimationPlayer.get(id);
if (!player) {
*errorString = "Could not find animation player with given id";
return 0;
}
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)
{
#if ENABLE(OILPAN)
visitor->trace(m_idToAnimationPlayer);
#endif
InspectorBaseAgent::trace(visitor);
}
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef InspectorAnimationAgent_h
#define InspectorAnimationAgent_h
#include "core/InspectorFrontend.h"
#include "core/inspector/InspectorBaseAgent.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/text/WTFString.h"
namespace blink {
class AnimationNode;
class AnimationPlayer;
class InspectorDOMAgent;
class InspectorAnimationAgent final : public InspectorBaseAgent<InspectorAnimationAgent>, public InspectorBackendDispatcher::AnimationCommandHandler {
WTF_MAKE_NONCOPYABLE(InspectorAnimationAgent);
public:
static PassOwnPtrWillBeRawPtr<InspectorAnimationAgent> create(InspectorDOMAgent* domAgent)
{
return adoptPtrWillBeNoop(new InspectorAnimationAgent(domAgent));
}
// Base agent methods.
virtual void setFrontend(InspectorFrontend*) override;
virtual void clearFrontend() override;
void reset();
// Protocol method implementations.
virtual void getAnimationPlayersForNode(ErrorString*, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::Animation::AnimationPlayer> >& animationPlayersArray) override;
virtual void pauseAnimationPlayer(ErrorString*, const String& id, RefPtr<TypeBuilder::Animation::AnimationPlayer>&) override;
virtual void playAnimationPlayer(ErrorString*, const String& id, RefPtr<TypeBuilder::Animation::AnimationPlayer>&) override;
virtual void setAnimationPlayerCurrentTime(ErrorString*, const String& id, double currentTime, RefPtr<TypeBuilder::Animation::AnimationPlayer>&) override;
virtual void getAnimationPlayerState(ErrorString*, const String& id, double* currentTime, bool* isRunning) override;
// Methods for other agents to use.
AnimationPlayer* assertAnimationPlayer(ErrorString*, const String& id);
virtual void trace(Visitor*) override;
private:
InspectorAnimationAgent(InspectorDOMAgent*);
String playerId(AnimationPlayer&);
PassRefPtr<TypeBuilder::Animation::AnimationPlayer> buildObjectForAnimationPlayer(AnimationPlayer&);
PassRefPtr<TypeBuilder::Animation::AnimationNode> buildObjectForAnimationNode(AnimationNode&);
RawPtrWillBeMember<InspectorDOMAgent> m_domAgent;
InspectorFrontend::Animation* m_frontend;
WillBeHeapHashMap<String, RefPtrWillBeMember<AnimationPlayer> > m_idToAnimationPlayer;
};
}
#endif // InspectorAnimationAgent_h
......@@ -37,6 +37,7 @@
#include "core/inspector/IdentifiersFactory.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/InspectorAnimationAgent.h"
#include "core/inspector/InspectorApplicationCacheAgent.h"
#include "core/inspector/InspectorCSSAgent.h"
#include "core/inspector/InspectorCanvasAgent.h"
......@@ -79,6 +80,7 @@ InspectorController::InspectorController(Page* page, InspectorClient* inspectorC
, m_cssAgent(nullptr)
, m_resourceAgent(nullptr)
, m_layerTreeAgent(nullptr)
, m_animationAgent(nullptr)
, m_inspectorFrontendClient(nullptr)
, m_page(page)
, m_inspectorClient(inspectorClient)
......@@ -99,7 +101,6 @@ InspectorController::InspectorController(Page* page, InspectorClient* inspectorC
m_domAgent = domAgentPtr.get();
m_agents.append(domAgentPtr.release());
OwnPtrWillBeRawPtr<InspectorLayerTreeAgent> layerTreeAgentPtr(InspectorLayerTreeAgent::create(m_page));
m_layerTreeAgent = layerTreeAgentPtr.get();
m_agents.append(layerTreeAgentPtr.release());
......@@ -137,6 +138,7 @@ void InspectorController::trace(Visitor* visitor)
visitor->trace(m_injectedScriptManager);
visitor->trace(m_state);
visitor->trace(m_domAgent);
visitor->trace(m_animationAgent);
visitor->trace(m_pageAgent);
visitor->trace(m_timelineAgent);
visitor->trace(m_cssAgent);
......@@ -185,6 +187,10 @@ void InspectorController::initializeDeferredAgents()
m_cssAgent = cssAgentPtr.get();
m_agents.append(cssAgentPtr.release());
OwnPtrWillBeRawPtr<InspectorAnimationAgent> animationAgentPtr(InspectorAnimationAgent::create(m_domAgent));
m_animationAgent = animationAgentPtr.get();
m_agents.append(animationAgentPtr.release());
m_agents.append(InspectorDOMStorageAgent::create(m_pageAgent));
m_agents.append(InspectorMemoryAgent::create());
......
......@@ -47,6 +47,7 @@ class GraphicsLayer;
class InjectedScriptManager;
class InspectorBackendDispatcher;
class InspectorAgent;
class InspectorAnimationAgent;
class InspectorClient;
class InspectorCSSAgent;
class InspectorDOMAgent;
......@@ -153,6 +154,7 @@ private:
RawPtrWillBeMember<InspectorResourceAgent> m_resourceAgent;
RawPtrWillBeMember<InspectorLayerTreeAgent> m_layerTreeAgent;
RawPtrWillBeMember<InspectorTracingAgent> m_tracingAgent;
RawPtrWillBeMember<InspectorAnimationAgent> m_animationAgent;
RefPtrWillBeMember<InspectorBackendDispatcher> m_inspectorBackendDispatcher;
InspectorFrontendClient* m_inspectorFrontendClient;
......
......@@ -125,6 +125,7 @@
'front_end/screencast/ScreencastView.js',
],
'devtools_sdk_js_files': [
'front_end/sdk/AnimationModel.js',
'front_end/sdk/ApplicationCacheModel.js',
'front_end/sdk/BlackboxSupport.js',
'front_end/sdk/ConsoleModel.js',
......@@ -370,6 +371,7 @@
'front_end/documentation/WikiParser.js',
],
'devtools_elements_js_files': [
'front_end/elements/AnimationsSidebarPane.js',
'front_end/elements/ElementsPanel.js',
'front_end/elements/ElementsTreeOutline.js',
'front_end/elements/EventListenersSidebarPane.js',
......
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @extends {WebInspector.SidebarPane}
*/
WebInspector.AnimationsSidebarPane = function(stylesPane)
{
WebInspector.SidebarPane.call(this, WebInspector.UIString("Animations"));
this._stylesPane = stylesPane;
this._emptyElement = document.createElement("div");
this._emptyElement.className = "info";
this._emptyElement.textContent = WebInspector.UIString("No Animations");
this.bodyElement.appendChild(this._emptyElement);
}
WebInspector.AnimationsSidebarPane.prototype = {
/**
* @param {?WebInspector.DOMNode} node
*/
update: function(node)
{
/**
* @param {?Array.<!WebInspector.AnimationModel.AnimationPlayer>} animationPlayers
* @this {WebInspector.AnimationsSidebarPane}
*/
function animationPlayersCallback(animationPlayers)
{
this.bodyElement.removeChildren();
this._animationSections = [];
if (!animationPlayers || !animationPlayers.length) {
this.bodyElement.appendChild(this._emptyElement);
return;
}
for (var i = 0; i < animationPlayers.length; ++i) {
var player = animationPlayers[i];
this._animationSections[i] = new WebInspector.AnimationSection(this, player);
var separatorElement = this.bodyElement.createChild("div", "sidebar-separator");
var id = player.source().name() ? player.source().name() : player.id();
separatorElement.createTextChild(WebInspector.UIString("Animation") + " " + id);
this.bodyElement.appendChild(this._animationSections[i].element);
}
}
if (this._selectedNode === node) {
for (var i = 0; i < this._animationSections.length; ++i)
this._animationSections[i].updateCurrentTime();
return;
}
this._selectedNode = node;
node.target().animationModel.animationPlayers(node.id, animationPlayersCallback.bind(this));
},
__proto__: WebInspector.SidebarPane.prototype
}
/**
* @constructor
* @param {!WebInspector.AnimationsSidebarPane} parentPane
* @param {?WebInspector.AnimationModel.AnimationPlayer} animationPlayer
*/
WebInspector.AnimationSection = function(parentPane, animationPlayer)
{
this._parentPane = parentPane;
this.propertiesSection = document.createElement("div");
this._setAnimationPlayer(animationPlayer);
this.element = document.createElement("div");
this.element.className = "styles-section";
this._updateThrottler = new WebInspector.Throttler(WebInspector.AnimationSection.updateTimeout);
this.element.appendChild(this._createAnimationControls());
this.element.appendChild(this.propertiesSection);
}
WebInspector.AnimationSection.updateTimeout = 100;
WebInspector.AnimationSection.prototype = {
updateCurrentTime: function()
{
this._updateThrottler.schedule(this._updateCurrentTime.bind(this), false);
},
/**
* @param {!WebInspector.Throttler.FinishCallback} finishCallback
*/
_updateCurrentTime: function(finishCallback)
{
/**
* @param {number} currentTime
* @param {boolean} isRunning
* @this {WebInspector.AnimationSection}
*/
function updateSliderCallback(currentTime, isRunning)
{
this.currentTimeSlider.value = this.player.source().iterationCount() == null ? currentTime % this.player.source().duration() : currentTime;
finishCallback();
if (isRunning && this._parentPane.isShowing())
this.updateCurrentTime();
}
this.player.getCurrentState(updateSliderCallback.bind(this));
},
/**
* @return {!Element}
*/
_createCurrentTimeSlider: function()
{
/**
* @param {!Event} e
* @this {WebInspector.AnimationSection}
*/
function sliderInputHandler(e)
{
this.player.setCurrentTime(parseFloat(e.target.value), this._setAnimationPlayer.bind(this));
}
var iterationDuration = this.player.source().duration();
var iterationCount = this.player.source().iterationCount();
var slider = document.createElement("input");
slider.type = "range";
slider.min = 0;
slider.step = 0.01;
if (!iterationCount) {
// Infinite iterations
slider.max = iterationDuration;
slider.value = this.player.currentTime() % iterationDuration;
} else {
slider.max = iterationCount * iterationDuration;
slider.value = this.player.currentTime();
}
slider.addEventListener("input", sliderInputHandler.bind(this));
this.updateCurrentTime();
return slider;
},
/**
* @return {!Element}
*/
_createAnimationControls: function()
{
/**
* @this {WebInspector.AnimationSection}
*/
function pauseButtonHandler()
{
if (this.player.paused()) {
this.player.play(this._setAnimationPlayer.bind(this));
updatePauseButton.call(this, false);
this.updateCurrentTime();
} else {
this.player.pause(this._setAnimationPlayer.bind(this));
updatePauseButton.call(this, true);
}
}
/**
* @param {boolean} paused
* @this {WebInspector.AnimationSection}
*/
function updatePauseButton(paused)
{
this._pauseButton.state = paused;
this._pauseButton.title = paused ? WebInspector.UIString("Play animation") : WebInspector.UIString("Pause animation");
}
this._pauseButton = new WebInspector.StatusBarButton("", "animation-pause");
updatePauseButton.call(this, this.player.paused());
this._pauseButton.addEventListener("click", pauseButtonHandler, this);
this.currentTimeSlider = this._createCurrentTimeSlider();
var controls = document.createElement("div");
controls.appendChild(this._pauseButton.element);
controls.appendChild(this.currentTimeSlider);
return controls;
},
/**
* @param {?WebInspector.AnimationModel.AnimationPlayer} p
*/
_setAnimationPlayer: function(p)
{
if (!p || p === this.player)
return;
this.player = p;
this.propertiesSection.removeChildren();
var animationObject = {
"playState": p.playState(),
"start-time": p.startTime(),
"player-playback-rate": p.playbackRate(),
"id": p.id(),
"start-delay": p.source().startDelay(),
"playback-rate": p.source().playbackRate(),
"iteration-start": p.source().iterationStart(),
"iteration-count": p.source().iterationCount(),
"duration": p.source().duration(),
"direction": p.source().direction(),
"fill-mode": p.source().fillMode(),
"time-fraction": p.source().timeFraction()
};
var obj = WebInspector.RemoteObject.fromLocalObject(animationObject);
var section = new WebInspector.ObjectPropertiesSection(obj, WebInspector.UIString("Animation Properties"));
this.propertiesSection.appendChild(section.element);
}
}
\ No newline at end of file
......@@ -80,12 +80,14 @@ WebInspector.ElementsPanel = function()
this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane();
this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this);
this.sidebarPanes.eventListeners = new WebInspector.EventListenersSidebarPane();
this.sidebarPanes.animations = new WebInspector.AnimationsSidebarPane(this.sidebarPanes.styles);
this.sidebarPanes.styles.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateStyles.bind(this, false));
this.sidebarPanes.metrics.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateMetrics.bind(this));
this.sidebarPanes.platformFonts.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updatePlatformFonts.bind(this));
this.sidebarPanes.properties.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateProperties.bind(this));
this.sidebarPanes.eventListeners.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateEventListeners.bind(this));
this.sidebarPanes.animations.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateAnimations.bind(this));
this.sidebarPanes.styles.addEventListener("style edited", this._stylesPaneEdited, this);
this.sidebarPanes.styles.addEventListener("style property toggled", this._stylesPaneEdited, this);
......@@ -300,6 +302,7 @@ WebInspector.ElementsPanel.prototype = {
this.updatePlatformFonts();
this.updateProperties();
this.updateEventListeners();
this.updateAnimations();
},
_reset: function()
......@@ -1133,6 +1136,15 @@ WebInspector.ElementsPanel.prototype = {
eventListenersSidebarPane.needsUpdate = false;
},
updateAnimations: function()
{
var animationsSidebarPane = this.sidebarPanes.animations;
if (!animationsSidebarPane.isShowing())
return;
animationsSidebarPane.update(this.selectedDOMNode());
},
/**
* @param {!KeyboardEvent} event
*/
......@@ -1415,6 +1427,8 @@ WebInspector.ElementsPanel.prototype = {
this.sidebarPaneView.addPane(this.sidebarPanes.eventListeners);
this.sidebarPaneView.addPane(this.sidebarPanes.domBreakpoints);
this.sidebarPaneView.addPane(this.sidebarPanes.properties);
if (Runtime.experiments.isEnabled("animationInspection"))
this.sidebarPaneView.addPane(this.sidebarPanes.animations);
this._extensionSidebarPanesContainer = this.sidebarPaneView;
for (var i = 0; i < this._extensionSidebarPanes.length; ++i)
......
......@@ -75,6 +75,7 @@
"PlatformFontsSidebarPane.js",
"PropertiesSidebarPane.js",
"StylesSidebarPane.js",
"ElementsPanel.js"
"ElementsPanel.js",
"AnimationsSidebarPane.js"
]
}
......@@ -716,3 +716,11 @@ li.child-editing .styles-clipboard-only {
overflow: hidden;
line-height: 16px;
}
.animation-pause .glyph {
-webkit-mask-position: -32px -72px;
}
.animation-pause.toggled-on .glyph {
-webkit-mask-position: 0 -72px;
}
\ No newline at end of file
......@@ -144,6 +144,7 @@ WebInspector.Main.prototype = {
_initializeExperiments: function()
{
Runtime.experiments.register("animationInspection", "Animation Inspection", true);
Runtime.experiments.register("applyCustomStylesheet", "Allow custom UI themes");
Runtime.experiments.register("canvasInspection", "Canvas inspection");
Runtime.experiments.register("devicesPanel", "Devices panel");
......
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @extends {WebInspector.SDKModel}
* @param {!WebInspector.Target} target
*/
WebInspector.AnimationModel = function(target) {
WebInspector.SDKModel.call(this, WebInspector.AnimationModel, target);
this._agent = target.animationAgent();
}
WebInspector.AnimationModel.prototype = {
/**
* @param {!DOMAgent.NodeId} nodeId
* @param {function(?Array.<!WebInspector.AnimationModel.AnimationPlayer>)} callback
*/
animationPlayers: function(nodeId, callback)
{
/**
* @param {?Protocol.Error} error
* @param {!Array.<!AnimationAgent.AnimationPlayer>} payloads
*/
function mycallback(error, payloads)
{
if (error) {
callback(null);
return;
}
callback(payloads.map(function(payload) {
return new WebInspector.AnimationModel.AnimationPlayer(target, payload);
}));
}
var target = this.target();
this._agent.getAnimationPlayersForNode(nodeId, mycallback);
},
__proto__: WebInspector.SDKModel.prototype
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!WebInspector.Target} target
* @param {!AnimationAgent.AnimationPlayer} payload
*/
WebInspector.AnimationModel.AnimationPlayer = function(target, payload)
{
WebInspector.SDKObject.call(this, target);
this._payload = payload;
this._source = new WebInspector.AnimationModel.AnimationNode(this.target(), this._payload.source);
}
WebInspector.AnimationModel.AnimationPlayer.prototype = {
/**
* @return {!AnimationAgent.AnimationPlayer}
*/
payload: function()
{
return this._payload;
},
/**
* @return {string}
*/
id: function()
{
return this._payload.id;
},
/**
* @return {boolean}
*/
paused: function ()
{
return this._payload.pausedState;
},
/**
* @return {string}
*/
playState: function()
{
return this._payload.playState;
},
/**
* @return {number}
*/
playbackRate: function()
{
return this._payload.playbackRate;
},
/**
* @return {number}
*/
startTime: function()
{
return this._payload.startTime;
},
/**
* @return {number}
*/
currentTime: function()
{
return this._payload.currentTime;
},
/**
* @return {!WebInspector.AnimationModel.AnimationNode}
*/
source: function()
{
return this._source;
},
/**
* @param {function(?WebInspector.AnimationModel.AnimationPlayer)} callback
*/
pause: function(callback)
{
var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "AnimationAgent.pauseAnimationPlayer(): ", WebInspector.AnimationModel.AnimationPlayer.bind(null, this._target));
this.target().animationModel._agent.pauseAnimationPlayer(this.id(), wrappedCallback);
},
/**
* @param {function(?WebInspector.AnimationModel.AnimationPlayer)} callback
*/
play: function(callback)
{
var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "AnimationAgent.playAnimationPlayer(): ", WebInspector.AnimationModel.AnimationPlayer.bind(null, this._target));
this.target().animationModel._agent.playAnimationPlayer(this.id(), wrappedCallback);
},
/**
* @param {number} currentTime
* @param {function(?WebInspector.AnimationModel.AnimationPlayer)} callback
*/
setCurrentTime: function(currentTime, callback)
{
var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "AnimationAgent.setAnimationPlayerCurrentTime(): ", WebInspector.AnimationModel.AnimationPlayer.bind(null, this._target));
this.target().animationModel._agent.setAnimationPlayerCurrentTime(this.id(), currentTime, wrappedCallback);
},
/**
* @param {function(number, boolean)} callback
*/
getCurrentState: function(callback)
{
/**
* @param {?Protocol.Error} error
* @param {number} currentTime
* @param {boolean} isRunning
*/
function mycallback(error, currentTime, isRunning)
{
if (error) {
console.error(error);
return;
}
callback(currentTime, isRunning);
}
this.target().animationModel._agent.getAnimationPlayerState(this.id(), mycallback);
},
__proto__: WebInspector.SDKObject.prototype
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!WebInspector.Target} target
* @param {!AnimationAgent.AnimationNode} payload
*/
WebInspector.AnimationModel.AnimationNode = function(target, payload)
{
WebInspector.SDKObject.call(this, target);
this._payload = payload;
}
WebInspector.AnimationModel.AnimationNode.prototype = {
/**
* @return {number}
*/
startDelay: function()
{
return this._payload.startDelay;
},
/**
* @return {number}
*/
playbackRate: function()
{
return this._payload.playbackRate;
},
/**
* @return {number}
*/
iterationStart: function()
{
return this._payload.iterationStart;
},
/**
* @return {number}
*/
iterationCount: function()
{
return this._payload.iterationCount;
},
/**
* @return {number}
*/
duration: function()
{
return this._payload.duration;
},
/**
* @return {number}
*/
direction: function()
{
return this._payload.direction;
},
/**
* @return {number}
*/
fillMode: function()
{
return this._payload.fillMode;
},
/**
* @return {number}
*/
timeFraction: function()
{
return this._payload.timeFraction;
},
/**
* @return {string}
*/
name: function()
{
return this._payload.name;
},
__proto__: WebInspector.SDKObject.prototype
}
\ No newline at end of file
......@@ -166,6 +166,9 @@ WebInspector.Target.prototype = {
/** @type {!WebInspector.LayerTreeModel} */
this.layerTreeModel = new WebInspector.LayerTreeModel(this);
/** @type {!WebInspector.AnimationModel} */
this.animationModel = new WebInspector.AnimationModel(this);
if (callback)
callback(this);
},
......
......@@ -7,6 +7,7 @@
"InspectorBackend.js",
"../InspectorBackendCommands.js",
"Target.js",
"AnimationModel.js",
"ApplicationCacheModel.js",
"BlackboxSupport.js",
"ConsoleModel.js",
......
......@@ -4411,5 +4411,104 @@
"handlers": ["browser", "frontend"]
}
]
},
{
"domain": "Animation",
"hidden": true,
"types": [
{
"id": "AnimationPlayer",
"type": "object",
"hidden": true,
"properties": [
{ "name": "id", "type": "string", "description": "<code>AnimationPlayer</code>'s id." },
{ "name": "pausedState", "type": "boolean", "hidden": "true", "description": "<code>AnimationPlayer</code>'s internal paused state." },
{ "name": "playState", "type": "string", "description": "<code>AnimationPlayer</code>'s play state." },
{ "name": "playbackRate", "type": "number", "description": "<code>AnimationPlayer</code>'s playback rate." },
{ "name": "startTime", "type": "number", "description": "<code>AnimationPlayer</code>'s start time." },
{ "name": "currentTime", "type": "number", "description": "<code>AnimationPlayer</code>'s current time." },
{ "name": "source", "$ref": "AnimationNode", "description": "<code>AnimationPlayer</code>'s source animation node." }
],
"description": "AnimationPlayer instance."
},
{
"id": "AnimationNode",
"type": "object",
"hidden": true,
"properties": [
{ "name": "startDelay", "type": "number", "description": "<code>AnimationNode</code>'s start delay." },
{ "name": "playbackRate", "type": "number", "description": "<code>AnimationNode</code>'s playbackRate." },
{ "name": "iterationStart", "type": "number", "description": "<code>AnimationNode</code>'s iteration start." },
{ "name": "iterationCount", "type": "number", "description": "<code>AnimationNode</code>'s iteration count." },
{ "name": "duration", "type": "number", "description": "<code>AnimationNode</code>'s iteration duration." },
{ "name": "direction", "type": "number", "description": "<code>AnimationNode</code>'s playback direction." },
{ "name": "fillMode", "type": "number", "description": "<code>AnimationNode</code>'s fill mode." },
{ "name": "timeFraction", "type": "number", "description": "<code>AnimationNode</code>'s time fraction." },
{ "name": "name", "type": "string", "description": "<code>AnimationNode</code> name."}
],
"description": "AnimationNode instance"
}
],
"commands": [
{
"name": "getAnimationPlayersForNode",
"parameters": [
{ "name": "nodeId", "$ref": "DOM.NodeId", "description": "Id of the node to get animation players for." }
],
"returns": [
{ "name": "animationPlayers", "type": "array", "items": { "$ref": "AnimationPlayer" }, "description": "Array of animation players." }
],
"description": "Returns animation players relevant to the node.",
"hidden": true
},
{
"name": "pauseAnimationPlayer",
"parameters": [
{ "name": "id", "type": "string", "description": "Id of the animation player." }
],
"returns": [
{ "name": "animationPlayer", "$ref": "AnimationPlayer", "description": "Animation Player with current time set." }
],
"description": "Pauses animations relevant to the node.",
"hidden": true
},
{
"name": "playAnimationPlayer",
"parameters": [
{ "name": "id", "type": "string", "description": "Id of the animation player." }
],
"returns": [
{ "name": "animationPlayer", "$ref": "AnimationPlayer", "description": "Animation Player with current time set." }
],
"description": "Plays animations relevant to the node.",
"hidden": true
},
{
"name": "setAnimationPlayerCurrentTime",
"parameters": [
{ "name": "id", "type": "string", "description": "Id of the animation player." },
{ "name": "currentTime", "type": "number", "description": "Current time to set animation to"}
],
"returns": [
{ "name": "animationPlayer", "$ref": "AnimationPlayer", "description": "Animation Player with current time set." }
],
"description": "Sets the current time on given AnimationPlayer.",
"hidden": true
},
{
"name": "getAnimationPlayerState",
"parameters": [
{ "name": "id", "type": "string", "description": "Id of the animation player." }
],
"returns": [
{ "name": "currentTime", "type": "number", "description": "Current time of the animation player." },
{ "name": "isRunning", "type": "boolean", "description": "If the animation player is still running." }
],
"description": "Gets the state of an AnimationPlayer.",
"hidden": true
}
],
"events": [
]
}]
}
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