#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
+#include <dali/devel-api/threading/mutex.h>
#include <dali/public-api/object/base-object.h>
#include <toolkit-application.h>
#include <toolkit-event-thread-callback.h>
bool Load(const std::string& url)
{
+ Dali::Mutex::ScopedLock lock(mMutex);
mUrl = url;
if(mUrl == "invalid.json")
{
{
// Change total frame number for test
mTotalFrameNumber = 200;
- mTestFrameDrop = true;
}
mDefaultWidth = 100;
void SetSize(uint32_t width, uint32_t height)
{
+ Dali::Mutex::ScopedLock lock(mMutex);
mWidth = width;
mHeight = height;
bool Render(uint32_t frameNumber)
{
+ Dali::Mutex::ScopedLock lock(mMutex);
if(mWidth == 0 || mHeight == 0)
{
return false;
void InvalidateBuffer()
{
- mNeedTrigger = true;
- mResourceReady = false;
+ Dali::Mutex::ScopedLock lock(mMutex);
+ if(mResourceReady)
+ {
+ mNeedTrigger = true;
+ mResourceReady = false;
+ }
}
Dali::VectorAnimationRenderer::UploadCompletedSignalType& UploadCompletedSignal()
std::string mUrl;
Dali::Renderer mRenderer;
+ Dali::Mutex mMutex;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mDefaultWidth;
{
void DelayRendering(uint32_t delay)
{
- Dali::Internal::Adaptor::gVectorAnimationRenderer->mDelayTime = delay;
+ Dali::Internal::Adaptor::gVectorAnimationRenderer->mDelayTime = delay;
+ Dali::Internal::Adaptor::gVectorAnimationRenderer->mTestFrameDrop = true;
}
uint32_t GetDroppedFrames()
application.SendNotification();
application.Render();
+ // Trigger count is 1 - load
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
visual.GetNaturalSize(naturalSize);
DALI_TEST_EQUALS(naturalSize, Vector2(100.0f, 100.0f), TEST_LOCATION); // 100x100 is the content default size.
application.GetScene().Add(actor2);
+ application.SendNotification();
+ application.Render();
+
// Trigger count is 4 - load & render a frame for each instance
DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(4), true, TEST_LOCATION);
application.GetScene().Add(actor);
+ application.SendNotification();
+ application.Render();
+
+ // Trigger count is 2 - load, render the first frame
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
Property::Map map = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
Property::Value* value = map.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
int totalFrameNumber = value->Get<int>();
application.SendNotification();
application.Render();
- // Trigger count is 3 - load, render the first frame & calculating frame drops
- DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+ // Trigger count is 1 - calculating frame drops
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
// Check dropped frame
uint32_t frames = Test::VectorAnimationRenderer::GetDroppedFrames();
void AnimatedVectorImageVisual::DoSetOffScene(Actor& actor)
{
StopAnimation();
- SendAnimationData();
+ TriggerVectorRasterization();
if(mImpl->mRenderer)
{
mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
}
- SendAnimationData();
+ TriggerVectorRasterization();
}
}
TriggerVectorRasterization();
}
-void AnimatedVectorImageVisual::OnResourceReady(bool success)
+void AnimatedVectorImageVisual::OnResourceReady(VectorAnimationTask::ResourceStatus status)
{
- mLoadFailed = !success;
-
- // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
- Actor actor = mPlacementActor.GetHandle();
- if(actor && !mRendererAdded)
+ if(status == VectorAnimationTask::ResourceStatus::LOADED)
{
- if(success)
- {
- actor.AddRenderer(mImpl->mRenderer);
- ResourceReady(Toolkit::Visual::ResourceStatus::READY);
- }
- else
+ if(mImpl->mEventObserver)
{
- Vector2 imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
- mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
- actor.AddRenderer(mImpl->mRenderer);
- ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ mImpl->mEventObserver->RelayoutRequest(*this);
}
+ }
+ else
+ {
+ mLoadFailed = status == VectorAnimationTask::ResourceStatus::FAILED ? true : false;
- mRendererAdded = true;
+ // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
+ Actor actor = mPlacementActor.GetHandle();
+ if(actor && !mRendererAdded)
+ {
+ if(!mLoadFailed)
+ {
+ actor.AddRenderer(mImpl->mRenderer);
+ ResourceReady(Toolkit::Visual::ResourceStatus::READY);
+ }
+ else
+ {
+ Vector2 imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+ mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+ actor.AddRenderer(mImpl->mRenderer);
+ ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
+ }
- DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Renderer is added (success = %d) [%p]\n", success, this);
+ mRendererAdded = true;
+ }
}
+
+ DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Renderer is added (status = %d) [%p]\n", status, this);
}
void AnimatedVectorImageVisual::OnAnimationFinished()
/**
* @brief Called when the resource is ready.
- * @param[in] success True if the texture load was successful. If false, then the resource failed to load.
+ * @param[in] status The resource status
*/
- void OnResourceReady(bool success);
+ void OnResourceReady(VectorAnimationTask::ResourceStatus status);
/**
* @brief Event callback from rasterize thread. This is called after the animation is finished.
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
if(mProcessorRegistered)
{
- Adaptor::Get().UnregisterProcessor(*this);
+ Adaptor::Get().UnregisterProcessor(*this, true);
}
for(auto observer : mLifecycleObservers)
if(!mProcessorRegistered)
{
- Adaptor::Get().RegisterProcessor(*this);
+ Adaptor::Get().RegisterProcessor(*this, true); // Use post processor to trigger after layoutting
mProcessorRegistered = true;
}
}
{
if(Adaptor::IsAvailable())
{
- Adaptor::Get().UnregisterProcessor(*this);
+ Adaptor::Get().UnregisterProcessor(*this, true);
mProcessorRegistered = false;
}
}
}
mEventCallbacks.clear();
- Adaptor::Get().UnregisterProcessor(*this);
+ Adaptor::Get().UnregisterProcessor(*this, true);
mProcessorRegistered = false;
}
if(mLoadRequest)
{
- bool result = Load();
- if(!result)
- {
- return false;
- }
+ return Load();
}
}
void VectorAnimationTask::OnUploadCompleted()
{
- mResourceReadySignal.Emit(true);
+ mResourceReadySignal.Emit(ResourceStatus::READY);
}
void VectorAnimationTask::OnLoadCompleted()
{
if(!mLoadFailed)
{
- if(mWidth == 0 && mHeight == 0)
- {
- uint32_t width, height;
- mVectorRenderer.GetDefaultSize(width, height);
-
- SetSize(width, height);
-
- mVectorAnimationThread.AddTask(this);
- }
+ mResourceReadySignal.Emit(ResourceStatus::LOADED);
}
else
{
- // Load failed
- mResourceReadySignal.Emit(false);
+ mResourceReadySignal.Emit(ResourceStatus::FAILED);
}
}
} // namespace Internal
class VectorAnimationTask : public RefObject, public ConnectionTracker
{
public:
- using ResourceReadySignalType = Signal<void(bool)>;
+ enum class ResourceStatus
+ {
+ LOADED, /// Resource is loaded
+ READY, /// Resource is ready
+ FAILED /// Resource is fail to load
+ };
+
+ using ResourceReadySignalType = Signal<void(ResourceStatus)>;
using TimePoint = std::chrono::time_point<std::chrono::steady_clock>;