From 91f3a7014e5633ea185eaf9a624bba52e71feff6 Mon Sep 17 00:00:00 2001 From: Heeyong Song Date: Fri, 11 Sep 2020 13:05:09 +0900 Subject: [PATCH] Ensure animation is not played when an actor is not on scene Change-Id: Iadfe60520ad14de6db2c1867bc6df223fa5bf10a --- automated-tests/src/dali/utc-Dali-Actor.cpp | 2 + automated-tests/src/dali/utc-Dali-Animation.cpp | 100 +++++++++++++++++++-- automated-tests/src/dali/utc-Dali-CustomActor.cpp | 16 ++-- automated-tests/src/dali/utc-Dali-TypeRegistry.cpp | 5 ++ dali/internal/event/actors/actor-impl.cpp | 5 ++ dali/internal/event/actors/actor-impl.h | 5 ++ dali/internal/event/animation/animation-impl.cpp | 2 +- dali/internal/event/common/object-impl.h | 9 ++ .../update/animation/scene-graph-animator.h | 3 + dali/internal/update/common/property-owner.cpp | 7 +- dali/internal/update/common/property-owner.h | 9 ++ dali/internal/update/nodes/node.cpp | 5 ++ dali/internal/update/nodes/node.h | 5 ++ 13 files changed, 159 insertions(+), 14 deletions(-) diff --git a/automated-tests/src/dali/utc-Dali-Actor.cpp b/automated-tests/src/dali/utc-Dali-Actor.cpp index f0aef23..0b2a35b 100644 --- a/automated-tests/src/dali/utc-Dali-Actor.cpp +++ b/automated-tests/src/dali/utc-Dali-Actor.cpp @@ -1296,6 +1296,8 @@ int UtcDaliActorGetCurrentSizeImmediate(void) DALI_TEST_CHECK(actor.GetTargetSize() == vector); + application.GetScene().Add(actor); + // Start the animation animation.Play(); diff --git a/automated-tests/src/dali/utc-Dali-Animation.cpp b/automated-tests/src/dali/utc-Dali-Animation.cpp index 629d3e4..7c229c0 100644 --- a/automated-tests/src/dali/utc-Dali-Animation.cpp +++ b/automated-tests/src/dali/utc-Dali-Animation.cpp @@ -2216,9 +2216,91 @@ int UtcDaliAnimationPlayP(void) END_TEST; } +int UtcDaliAnimationPlayOffSceneP(void) +{ + // Test that an animation cannot be played, when the actor is off-stage. + // And the property value and the current property value should not be changed in the case. + + TestApplication application; + + Actor actor = Actor::New(); + Vector3 basePosition(Vector3::ZERO); + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); + // Not added to the stage yet! + + // Build the animation + float durationSeconds(1.0f); + Animation animation = Animation::New(durationSeconds); + Vector3 targetPosition(100.0f, 100.0f, 100.0f); + animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR); + + // Start the animation + animation.Play(); + + bool signalReceived(false); + AnimationFinishCheck finishCheck(signalReceived); + animation.FinishedSignal().Connect(&application, finishCheck); + + application.SendNotification(); + application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + + application.SendNotification(); + finishCheck.CheckSignalReceived(); + + // An animation can't be played. The position shouldn't be changed. + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); + + // Add to the stage + application.GetScene().Add(actor); + + // Start the animation again + animation.Play(); + + application.SendNotification(); + application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + + // We did expect the animation to finish + application.SendNotification(); + finishCheck.CheckSignalReceived(); + + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), targetPosition, TEST_LOCATION); + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION), targetPosition, TEST_LOCATION); + + // Reset the position + actor[Actor::Property::POSITION] = basePosition; + + application.SendNotification(); + application.Render(); + + // Create an animator again + animation.Clear(); + animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR); + + // Remove from the stage + application.GetScene().Remove(actor); + + signalReceived = false; + + // Start the animation again + animation.Play(); + + application.SendNotification(); + application.Render(static_cast(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/); + + application.SendNotification(); + finishCheck.CheckSignalReceived(); + + // An animation can't be played. The position shouldn't be changed. + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); + DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); + + END_TEST; +} + int UtcDaliAnimationPlayOffSceneDiscardP(void) { - // Test that an animation can be played, when the actor is off-stage. + // Test that an animation cannot be played, when the actor is off-stage. // When the actor is added to the stage, it should appear at the current position // i.e. where it would have been anyway, if on-stage from the beginning. @@ -2249,7 +2331,9 @@ int UtcDaliAnimationPlayOffSceneDiscardP(void) // We didn't expect the animation to finish yet application.SendNotification(); finishCheck.CheckSignalNotReceived(); - DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), Vector3(20, 20, 20), TEST_LOCATION); + + // An animation can't be played. The position shouldn't be changed. + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); // Add to the stage application.GetScene().Add(actor); @@ -2310,7 +2394,7 @@ int UtcDaliAnimationPlayOffSceneDiscardP(void) int UtcDaliAnimationPlayOffSceneBakeFinalP(void) { - // Test that an animation can be played, when the actor is off-stage. + // Test that an animation cannot be played, when the actor is off-stage. // When the actor is added to the stage, it should appear at the current position // i.e. where it would have been anyway, if on-stage from the beginning. @@ -2340,7 +2424,9 @@ int UtcDaliAnimationPlayOffSceneBakeFinalP(void) // We didn't expect the animation to finish yet application.SendNotification(); finishCheck.CheckSignalNotReceived(); - DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), Vector3(20, 20, 20), TEST_LOCATION); + + // An animation can't be played. The position shouldn't be changed. + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); // Add to the stage application.GetScene().Add(actor); @@ -2394,7 +2480,7 @@ int UtcDaliAnimationPlayOffSceneBakeFinalP(void) int UtcDaliAnimationPlayOffSceneBakeP(void) { - // Test that an animation can be played, when the actor is off-stage. + // Test that an animation cannot be played, when the actor is off-stage. // When the actor is added to the stage, it should appear at the current position // i.e. where it would have been anyway, if on-stage from the beginning. @@ -2425,7 +2511,9 @@ int UtcDaliAnimationPlayOffSceneBakeP(void) // We didn't expect the animation to finish yet application.SendNotification(); finishCheck.CheckSignalNotReceived(); - DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), Vector3(20, 20, 20), TEST_LOCATION); + + // An animation can't be played. The position shouldn't be changed. + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), basePosition, TEST_LOCATION); // Add to the stage application.GetScene().Add(actor); diff --git a/automated-tests/src/dali/utc-Dali-CustomActor.cpp b/automated-tests/src/dali/utc-Dali-CustomActor.cpp index 6dd051c..208f563 100644 --- a/automated-tests/src/dali/utc-Dali-CustomActor.cpp +++ b/automated-tests/src/dali/utc-Dali-CustomActor.cpp @@ -950,6 +950,8 @@ int UtcDaliCustomActorOnSizeAnimation(void) Test::TestCustomActor custom = Test::TestCustomActor::New(); DALI_TEST_EQUALS(0, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); + application.GetScene().Add(custom); + Animation anim = Animation::New(1.0f); anim.AnimateTo(Property(custom, Actor::Property::SIZE), Vector3(8.0f, 9.0f, 10.0f)); anim.Play(); @@ -957,8 +959,8 @@ int UtcDaliCustomActorOnSizeAnimation(void) application.SendNotification(); application.Render(static_cast(1000.0f)); - DALI_TEST_EQUALS(1, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); - DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[0], TEST_LOCATION); + DALI_TEST_EQUALS(2, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); + DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[1], TEST_LOCATION); DALI_TEST_EQUALS(8.0f, custom.GetTargetSize().width, TEST_LOCATION); DALI_TEST_EQUALS(9.0f, custom.GetTargetSize().height, TEST_LOCATION); DALI_TEST_EQUALS(10.0f, custom.GetTargetSize().depth, TEST_LOCATION); @@ -974,24 +976,26 @@ int UtcDaliCustomActorSizeComponentAnimation(void) float intialWidth(10.0f); DALI_TEST_EQUALS(0, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); + custom.SetProperty(Actor::Property::SIZE, Vector2(intialWidth, 10.0f)); // First method + application.GetScene().Add(custom); Animation anim = Animation::New(1.0f); - DALI_TEST_EQUALS(2, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); + DALI_TEST_EQUALS(3, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); anim.AnimateTo(Property(custom, Actor::Property::SIZE_WIDTH), 20.0f); - DALI_TEST_EQUALS(2, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); + DALI_TEST_EQUALS(3, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); anim.Play(); // Triggers second method ( OnSizeAnimation ) application.SendNotification(); application.Render(static_cast(1000.0f)); - DALI_TEST_EQUALS(3, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); + DALI_TEST_EQUALS(4, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION); - DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[2], TEST_LOCATION); + DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[3], TEST_LOCATION); END_TEST; } diff --git a/automated-tests/src/dali/utc-Dali-TypeRegistry.cpp b/automated-tests/src/dali/utc-Dali-TypeRegistry.cpp index c971314..fd7f134 100644 --- a/automated-tests/src/dali/utc-Dali-TypeRegistry.cpp +++ b/automated-tests/src/dali/utc-Dali-TypeRegistry.cpp @@ -1393,6 +1393,8 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationP(void) unsigned int customActorIndices = indices.Size(); DALI_TEST_EQUALS(actorIndices + 3u, customActorIndices, TEST_LOCATION); // Custom property + registered property + application.GetScene().Add(customActor); + // Attempt to animate component property, it should not crash Animation animation = Animation::New(1.0f); animation.AnimateTo(Property(customActor, animatablePropertyComponentIndex1), 200.0f); @@ -1416,6 +1418,7 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationVector2AnimateByP( BaseHandle handle = typeInfo.CreateInstance(); DALI_TEST_CHECK(handle); Actor customActor = Actor::DownCast(handle); + application.GetScene().Add(customActor); DALI_TEST_CHECK(customActor); const unsigned int index = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX; @@ -1469,6 +1472,7 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationVector3AnimateByP( BaseHandle handle = typeInfo.CreateInstance(); DALI_TEST_CHECK(handle); Actor customActor = Actor::DownCast(handle); + application.GetScene().Add(customActor); DALI_TEST_CHECK(customActor); const unsigned int index = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX; @@ -1528,6 +1532,7 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationVector4AnimateByP( BaseHandle handle = typeInfo.CreateInstance(); DALI_TEST_CHECK(handle); Actor customActor = Actor::DownCast(handle); + application.GetScene().Add(customActor); DALI_TEST_CHECK(customActor); const unsigned int index = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX; diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index 4911842..6b3386a 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -3496,6 +3496,11 @@ int32_t Actor::GetPropertyComponentIndex( Property::Index index ) const return componentIndex; } +bool Actor::IsAnimationPossible() const +{ + return OnScene(); +} + void Actor::SetParent( Actor* parent ) { if( parent ) diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h index 6573930..379667b 100644 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -1679,6 +1679,11 @@ public: int32_t GetPropertyComponentIndex( Property::Index index ) const override; /** + * @copydoc Dali::Internal::Object::IsAnimationPossible() + */ + bool IsAnimationPossible() const override; + + /** * Retrieve the actor's node. * @return The node used by this actor */ diff --git a/dali/internal/event/animation/animation-impl.cpp b/dali/internal/event/animation/animation-impl.cpp index 92791da..dde0a5a 100644 --- a/dali/internal/event/animation/animation-impl.cpp +++ b/dali/internal/event/animation/animation-impl.cpp @@ -1108,7 +1108,7 @@ void Animation::NotifyObjects( Animation::Notify notifyValueType ) AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ]; Object* object = connector->GetObject(); - if( object ) + if(object && object->IsAnimationPossible()) { const auto propertyIndex = connector->GetPropertyIndex(); object->NotifyPropertyAnimation( diff --git a/dali/internal/event/common/object-impl.h b/dali/internal/event/common/object-impl.h index 5e3afb1..41abd4a 100644 --- a/dali/internal/event/common/object-impl.h +++ b/dali/internal/event/common/object-impl.h @@ -349,6 +349,15 @@ public: virtual int32_t GetPropertyComponentIndex( Property::Index index ) const; /** + * Query whether playing an animation is possible or not. + * @return true if playing an animation is possible. + */ + virtual bool IsAnimationPossible() const + { + return true; + } + + /** * @copydoc Dali::Handle::PropertySetSignal() */ Handle::PropertySetSignalType& PropertySetSignal(); diff --git a/dali/internal/update/animation/scene-graph-animator.h b/dali/internal/update/animation/scene-graph-animator.h index 1cc6ab6..120aa24 100644 --- a/dali/internal/update/animation/scene-graph-animator.h +++ b/dali/internal/update/animation/scene-graph-animator.h @@ -222,6 +222,9 @@ public: { mConnectedToSceneGraph = true; mPropertyOwner->AddObserver(*this); + + // Enable if the target object is valid and connected to the scene graph. + mEnabled = mPropertyOwner->IsAnimationPossible(); } /** diff --git a/dali/internal/update/common/property-owner.cpp b/dali/internal/update/common/property-owner.cpp index 0d915a1..8d560ca 100644 --- a/dali/internal/update/common/property-owner.cpp +++ b/dali/internal/update/common/property-owner.cpp @@ -89,6 +89,8 @@ void PropertyOwner::Destroy() void PropertyOwner::ConnectToSceneGraph() { + mIsConnectedToSceneGraph = true; + // Notification for observers const ConstObserverIter endIter = mObservers.End(); for( ConstObserverIter iter = mObservers.Begin(); iter != endIter; ++iter) @@ -99,6 +101,8 @@ void PropertyOwner::ConnectToSceneGraph() void PropertyOwner::DisconnectFromSceneGraph( BufferIndex updateBufferIndex ) { + mIsConnectedToSceneGraph = false; + // Notification for observers const ConstObserverIter endIter = mObservers.End(); for( ConstObserverIter iter = mObservers.Begin(); iter != endIter; ++iter) @@ -143,7 +147,8 @@ void PropertyOwner::RemoveConstraint( ConstraintBase* constraint ) } PropertyOwner::PropertyOwner() -: mUpdated( false ) +: mUpdated(false), + mIsConnectedToSceneGraph(false) { } diff --git a/dali/internal/update/common/property-owner.h b/dali/internal/update/common/property-owner.h index c4dd922..5fbfc5a 100644 --- a/dali/internal/update/common/property-owner.h +++ b/dali/internal/update/common/property-owner.h @@ -223,6 +223,14 @@ public: */ void RemoveUniformMapObserver( UniformMap::Observer& observer ); + /** + * Query whether playing an animation is possible or not. + * @return true if playing an animation is possible. + */ + virtual bool IsAnimationPossible() const + { + return true; + } protected: @@ -244,6 +252,7 @@ protected: OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty() UniformMap mUniformMaps; ///< Container of owned uniform maps bool mUpdated; + bool mIsConnectedToSceneGraph; private: using ObserverContainer = Dali::Vector; diff --git a/dali/internal/update/nodes/node.cpp b/dali/internal/update/nodes/node.cpp index 189d18c..ae6dd7f 100755 --- a/dali/internal/update/nodes/node.cpp +++ b/dali/internal/update/nodes/node.cpp @@ -188,6 +188,11 @@ void Node::RemoveUniformMapping( const std::string& uniformName ) mRegenerateUniformMap = 2; } +bool Node::IsAnimationPossible() const +{ + return mIsConnectedToSceneGraph; +} + void Node::PrepareRender( BufferIndex bufferIndex ) { if( mRegenerateUniformMap != 0 ) diff --git a/dali/internal/update/nodes/node.h b/dali/internal/update/nodes/node.h index c89c245..7e5a05d 100644 --- a/dali/internal/update/nodes/node.h +++ b/dali/internal/update/nodes/node.h @@ -806,6 +806,11 @@ public: void RemoveUniformMapping( const std::string& uniformName ) override; /** + * @copydoc Dali::Internal::SceneGraph::PropertyOwner::IsAnimationPossible + */ + bool IsAnimationPossible() const override; + + /** * Prepare the node for rendering. * This is called by the UpdateManager when an object is due to be rendered in the current frame. * @param[in] updateBufferIndex The current update buffer index. -- 2.7.4