Merge "DALi Version 2.1.32" into devel/master
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 22 Jul 2022 13:30:15 +0000 (13:30 +0000)
committerGerrit Code Review <gerrit@review>
Fri, 22 Jul 2022 13:30:15 +0000 (13:30 +0000)
16 files changed:
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
dali-toolkit/devel-api/controls/control-devel.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.h
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.h

index e6456ec..a8f3ab8 100644 (file)
@@ -129,6 +129,11 @@ public:
       mNeedDroppedFrames = false;
     }
 
+    if(mDynamicPropertyCallback)
+    {
+      CallbackBase::ExecuteReturn<Property::Value>(*mDynamicPropertyCallback, 0, 0, frameNumber);
+    }
+
     if(mNeedTrigger)
     {
       mEventThreadCallback->Trigger();
@@ -190,6 +195,11 @@ public:
     }
   }
 
+  void AddPropertyValueCallback(const std::string& keyPath, Dali::VectorAnimationRenderer::VectorProperty property, CallbackBase* callback, int32_t id)
+  {
+    mDynamicPropertyCallback = std::unique_ptr<CallbackBase>(callback);
+  }
+
   Dali::VectorAnimationRenderer::UploadCompletedSignalType& UploadCompletedSignal()
   {
     return mUploadCompletedSignal;
@@ -216,23 +226,25 @@ public:
 public:
   static uint32_t mCount;
 
-  std::string    mUrl;
-  Dali::Renderer mRenderer;
-  Dali::Mutex    mMutex;
-  uint32_t       mWidth;
-  uint32_t       mHeight;
-  uint32_t       mDefaultWidth;
-  uint32_t       mDefaultHeight;
-  uint32_t       mTotalFrameNumber;
-  uint32_t       mPreviousFrame;
-  uint32_t       mDelayTime;
-  uint32_t       mDroppedFrames;
-  float          mFrameRate;
-  bool           mTestFrameDrop;
-  bool           mNeedDroppedFrames;
-  bool           mLoadFailed{false};
-  bool           mResourceReady{false};
-  bool           mNeedTrigger{true};
+  std::string                   mUrl;
+  Dali::Renderer                mRenderer;
+  Dali::Mutex                   mMutex;
+  std::unique_ptr<CallbackBase> mDynamicPropertyCallback{nullptr};
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+  uint32_t mDefaultWidth;
+  uint32_t mDefaultHeight;
+  uint32_t mTotalFrameNumber;
+  uint32_t mPreviousFrame;
+  uint32_t mDelayTime;
+  uint32_t mDroppedFrames;
+  float    mFrameRate;
+  bool     mTestFrameDrop;
+  bool     mNeedDroppedFrames;
+  bool     mLoadFailed{false};
+  bool     mResourceReady{false};
+  bool     mNeedTrigger{true};
 
   Dali::VectorAnimationRenderer::UploadCompletedSignalType mUploadCompletedSignal;
   std::unique_ptr<EventThreadCallback>                     mEventThreadCallback;
@@ -348,6 +360,11 @@ void VectorAnimationRenderer::InvalidateBuffer()
   return Internal::Adaptor::GetImplementation(*this).InvalidateBuffer();
 }
 
+void VectorAnimationRenderer::AddPropertyValueCallback(const std::string& keyPath, VectorProperty property, CallbackBase* callback, int32_t id)
+{
+  Internal::Adaptor::GetImplementation(*this).AddPropertyValueCallback(keyPath, property, callback, id);
+}
+
 VectorAnimationRenderer::UploadCompletedSignalType& VectorAnimationRenderer::UploadCompletedSignal()
 {
   return Internal::Adaptor::GetImplementation(*this).UploadCompletedSignal();
index 0529655..4ca6308 100644 (file)
@@ -34,6 +34,8 @@
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
 
@@ -709,8 +711,9 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
 
-  Property::Map    map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
-  Property::Value* value = map.Find(DevelImageVisual::Property::PLAY_RANGE);
+  Property::Map    map              = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+  Property::Value* value            = map.Find(DevelImageVisual::Property::PLAY_RANGE);
+  int              totalFrameNumber = map.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER)->Get<int>();
 
   int              resultStartFrame, resultEndFrame;
   Property::Array* result = value->GetArray();
@@ -744,8 +747,8 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
   result->GetElementAt(0).Get(resultStartFrame);
   result->GetElementAt(1).Get(resultEndFrame);
 
-  DALI_TEST_EQUALS(startFrame, resultStartFrame, TEST_LOCATION); // Should not be changed
-  DALI_TEST_EQUALS(endFrame, resultEndFrame, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultStartFrame, 1, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultEndFrame, totalFrameNumber - 1, TEST_LOCATION); // Should be clamped
 
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, Property::Map());
 
@@ -1854,8 +1857,14 @@ int UtcDaliAnimatedVectorImageVisualSize(void)
 
   application.SendNotification();
 
-  // Trigger count is 2 - load, resource ready
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+  // Trigger count is 1 - load
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - resource ready
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   textureTrace.Enable(true);
 
@@ -1891,3 +1900,63 @@ int UtcDaliAnimatedVectorImageVisualSize(void)
 
   END_TEST;
 }
+
+namespace
+{
+bool gDynamicPropertyCallbackFired = false;
+
+Property::Value FillColorCallback(int32_t id, VectorAnimationRenderer::VectorProperty property, uint32_t frameNumber)
+{
+  gDynamicPropertyCallbackFired = true;
+
+  if(frameNumber < 3)
+  {
+    return Vector3(0, 0, 1);
+  }
+  else
+  {
+    return Vector3(1, 0, 0);
+  }
+}
+} // namespace
+
+int UtcDaliAnimatedVectorImageVisualDynamicProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedVectorImageVisualDynamicProperty");
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base  visual  = factory.CreateVisual(TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions());
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      actor     = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+  application.GetScene().Add(actor);
+
+  gDynamicPropertyCallbackFired = false;
+
+  // Set dynamic property
+  DevelAnimatedVectorImageVisual::DynamicPropertyInfo info;
+  info.id       = 1;
+  info.keyPath  = "Test.Path";
+  info.property = static_cast<int>(VectorAnimationRenderer::VectorProperty::FILL_COLOR);
+  info.callback = MakeCallback(FillColorCallback);
+
+  DevelControl::DoActionExtension(actor, DummyControl::Property::TEST_VISUAL, DevelAnimatedVectorImageVisual::Action::SET_DYNAMIC_PROPERTY, Any(info));
+
+  Property::Map attributes;
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - load & render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  // Test whether the property callback is called
+  DALI_TEST_EQUALS(gDynamicPropertyCallbackFired, true, TEST_LOCATION);
+
+  END_TEST;
+}
index 51e0564..ef1265b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -114,6 +114,13 @@ void DoAction(Control& control, Dali::Property::Index visualIndex, Dali::Propert
   controlDataImpl.DoAction(visualIndex, actionId, attributes);
 }
 
+void DoActionExtension(Control& control, Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes)
+{
+  Internal::Control&       controlInternal = Toolkit::Internal::GetImplementation(control);
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlInternal);
+  controlDataImpl.DoActionExtension(visualIndex, actionId, attributes);
+}
+
 void SetInputMethodContext(Internal::Control& control, InputMethodContext& inputMethodContext)
 {
   Internal::Control::Impl::Get(control).SetInputMethodContext(inputMethodContext);
index 3a94e1b..fe95c70 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_DEVEL_H
 
 /*
- * 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.
@@ -368,6 +368,18 @@ DALI_TOOLKIT_API Dali::Animation CreateTransition(Internal::Control&
 DALI_TOOLKIT_API void DoAction(Control& control, Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes);
 
 /**
+ * @brief Perform an action on a visual registered to this control.
+ *
+ * Visuals will have actions, this API is used to perform one of these actions with the given attributes.
+ *
+ * @param[in] control The control.
+ * @param[in] visualIndex The Property index of the visual.
+ * @param[in] actionId The action to perform.  See Visual to find supported actions.
+ * @param[in] attributes Optional attributes for the action.
+ */
+DALI_TOOLKIT_API void DoActionExtension(Control& control, Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes);
+
+/**
  * @brief Set input method context.
  *
  * @param[in] control The control.
index ecb91ae..33c88e0 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_ACTIONS_DEVEL_H
 
 /*
- * Copyright (c) 2020 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.
  * limitations under the License.
  *
  */
+
+// EXTERNAL INCLUDES
 #include <dali-toolkit/devel-api/toolkit-action-index-ranges.h>
+#include <dali/public-api/signals/callback.h>
+#include <string>
 
 namespace Dali
 {
@@ -39,10 +43,35 @@ enum Type
   PAUSE,                            ///< Pause the animated vector image.
   STOP,                             ///< Stop the animated vector image. This is also Default playback mode.
   JUMP_TO,                          ///< Jump to the specified frame. Property::INTEGER value should be passed.
+  SET_DYNAMIC_PROPERTY              ///< Set the dynamic property.
 };
 
 } // namespace Action
 
+/**
+ * @brief The dynamic property info
+ *
+ * @note A callback of the following type may be used:
+ * @code
+ *   Property::Value MyFunction(int32_t id, VectorAnimationRenderer::VectorProperty property, uint32_t frameNumber);
+ * @endcode
+ *
+ * id  The id to specify the callback.
+ * property The property that represent what you are trying to change.
+ * frameNumber The current frame number.
+ * It returns a Property::Value to set according to the property type.
+ *
+ * The callback will be called on the worker thread. You MUST not call other DALi methods in the callback.
+ * And the object must still be alive when the callback occurs if you make the callback from a class member function.
+ */
+struct DynamicPropertyInfo
+{
+  int32_t       id;       ///< The Id to specify the callback. It should be unique and will be passed when the callback is called.
+  std::string   keyPath;  ///< The key path used to target a specific content or a set of contents that will be updated.
+  int32_t       property; ///< The property to set.
+  CallbackBase* callback; ///< The callback that gets called every time the animation is rendered. Ownership of the callback is passed onto the visual.
+};
+
 } // namespace DevelAnimatedVectorImageVisual
 
 } // namespace Toolkit
index b967d14..4c74704 100644 (file)
@@ -1096,6 +1096,15 @@ void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::
   }
 }
 
+void Control::Impl::DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes)
+{
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(visualIndex, mVisuals, iter))
+  {
+    Toolkit::GetImplementation((*iter)->visual).DoActionExtension(actionId, attributes);
+  }
+}
+
 void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
 {
   Property::Value* checkedValue = mAccessibilityAttributes.Find(key);
index 793fc22..46cc97b 100644 (file)
@@ -224,6 +224,11 @@ public:
   void DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes);
 
   /**
+   * @copydoc Dali::Toolkit::DevelControl::DoActionExtension()
+   */
+  void DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes);
+
+  /**
    * @brief Function used to set control properties.
    * @param[in] object The object whose property to set
    * @param[in] index The index of the property to set
index 4b547b4..1f73f80 100644 (file)
@@ -489,6 +489,22 @@ void AnimatedVectorImageVisual::OnDoAction(const Property::Index actionId, const
   TriggerVectorRasterization();
 }
 
+void AnimatedVectorImageVisual::OnDoActionExtension(const Property::Index actionId, Dali::Any attributes)
+{
+  switch(actionId)
+  {
+    case DevelAnimatedVectorImageVisual::Action::SET_DYNAMIC_PROPERTY:
+    {
+      DevelAnimatedVectorImageVisual::DynamicPropertyInfo info = AnyCast<DevelAnimatedVectorImageVisual::DynamicPropertyInfo>(attributes);
+      mAnimationData.dynamicProperties.push_back(info);
+      mAnimationData.resendFlag |= VectorAnimationTask::RESEND_DYNAMIC_PROPERTY;
+      break;
+    }
+  }
+
+  TriggerVectorRasterization();
+}
+
 void AnimatedVectorImageVisual::OnResourceReady(VectorAnimationTask::ResourceStatus status)
 {
   if(status == VectorAnimationTask::ResourceStatus::LOADED)
index 221cf23..72c8e60 100644 (file)
@@ -159,6 +159,11 @@ protected:
    */
   void OnDoAction(const Property::Index actionId, const Property::Value& attributes) override;
 
+  /**
+   * @copydoc Visual::Base::OnDoActionExtension
+   */
+  void OnDoActionExtension(const Property::Index actionId, Dali::Any attributes) override;
+
 private:
   /**
    * Helper method to set individual values by index key.
index b79f422..a202747 100644 (file)
@@ -95,6 +95,10 @@ void VectorAnimationTask::Finalize()
   {
     mAnimationFinishedTrigger.reset();
   }
+  if(mLoadCompletedTrigger)
+  {
+    mLoadCompletedTrigger.reset();
+  }
 
   mVectorRenderer.Finalize();
 
@@ -144,6 +148,11 @@ void VectorAnimationTask::RequestLoad(const std::string& url)
   mVectorAnimationThread.AddTask(this);
 }
 
+bool VectorAnimationTask::IsLoadRequested() const
+{
+  return mLoadRequest;
+}
+
 void VectorAnimationTask::SetAnimationData(const AnimationData& data)
 {
   ConditionalWait::ScopedLock lock(mConditionalWait);
@@ -280,38 +289,33 @@ void VectorAnimationTask::SetPlayRange(const Property::Array& playRange)
   }
 
   // Make sure the range specified is between 0 and the total frame number
-  if(startFrame < mTotalFrame && endFrame < mTotalFrame)
+  startFrame = std::min(startFrame, mTotalFrame - 1);
+  endFrame   = std::min(endFrame, mTotalFrame - 1);
+
+  // If the range is not in order swap values
+  if(startFrame > endFrame)
+  {
+    uint32_t temp = startFrame;
+    startFrame    = endFrame;
+    endFrame      = temp;
+  }
+
+  if(startFrame != mStartFrame || endFrame != mEndFrame)
   {
-    // If the range is not in order swap values
-    if(startFrame > endFrame)
+    mStartFrame = startFrame;
+    mEndFrame   = endFrame;
+
+    // If the current frame is out of the range, change the current frame also.
+    if(mStartFrame > mCurrentFrame)
     {
-      uint32_t temp = startFrame;
-      startFrame    = endFrame;
-      endFrame      = temp;
+      mCurrentFrame = mStartFrame;
     }
-
-    if(startFrame != mStartFrame || endFrame != mEndFrame)
+    else if(mEndFrame < mCurrentFrame)
     {
-      mStartFrame = startFrame;
-      mEndFrame   = endFrame;
-
-      // If the current frame is out of the range, change the current frame also.
-      if(mStartFrame > mCurrentFrame)
-      {
-        mCurrentFrame = mStartFrame;
-      }
-      else if(mEndFrame < mCurrentFrame)
-      {
-        mCurrentFrame = mEndFrame;
-      }
-
-      DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mUrl.c_str(), this);
+      mCurrentFrame = mEndFrame;
     }
-  }
-  else
-  {
-    DALI_LOG_ERROR("VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%s] [%p]\n", startFrame, endFrame, mUrl.c_str(), this);
-    return;
+
+    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mUrl.c_str(), this);
   }
 }
 
@@ -627,6 +631,14 @@ void VectorAnimationTask::ApplyAnimationData()
     mVectorRenderer.InvalidateBuffer();
   }
 
+  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY)
+  {
+    for(auto&& iter : mAnimationData[index].dynamicProperties)
+    {
+      mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast<VectorAnimationRenderer::VectorProperty>(iter.property), iter.callback, iter.id);
+    }
+  }
+
   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
   {
     if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING)
@@ -643,6 +655,8 @@ void VectorAnimationTask::ApplyAnimationData()
     }
   }
 
+  // reset data
+  mAnimationData[index].dynamicProperties.clear();
   mAnimationData[index].resendFlag = 0;
 }
 
index 1e4ff4c..42d13f8 100644 (file)
 #include <dali/devel-api/adaptor-framework/event-thread-callback.h>
 #include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
 #include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/object/property-array.h>
 #include <chrono>
 #include <memory>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 
 namespace Dali
@@ -54,7 +56,8 @@ public:
 
   using ResourceReadySignalType = Signal<void(ResourceStatus)>;
 
-  using TimePoint = std::chrono::time_point<std::chrono::steady_clock>;
+  using TimePoint           = std::chrono::time_point<std::chrono::steady_clock>;
+  using DynamicPropertyType = std::vector<DevelAnimatedVectorImageVisual::DynamicPropertyInfo>;
 
   /**
    * Flags for re-sending data to the vector animation thread
@@ -68,7 +71,8 @@ public:
     RESEND_CURRENT_FRAME       = 1 << 4,
     RESEND_SIZE                = 1 << 5,
     RESEND_PLAY_STATE          = 1 << 6,
-    RESEND_NEED_RESOURCE_READY = 1 << 7
+    RESEND_NEED_RESOURCE_READY = 1 << 7,
+    RESEND_DYNAMIC_PROPERTY    = 1 << 8
   };
 
   /**
@@ -79,6 +83,7 @@ public:
     AnimationData()
     : resendFlag(0),
       playRange(),
+      dynamicProperties(),
       playState(),
       stopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
       loopingMode(DevelImageVisual::LoopingMode::RESTART),
@@ -100,11 +105,13 @@ public:
       width        = rhs.width;
       height       = rhs.height;
       loopCount    = rhs.loopCount;
+      dynamicProperties.insert(dynamicProperties.end(), rhs.dynamicProperties.begin(), rhs.dynamicProperties.end());
       return *this;
     }
 
     uint32_t                             resendFlag;
     Property::Array                      playRange;
+    DynamicPropertyType                  dynamicProperties;
     DevelImageVisual::PlayState::Type    playState;
     DevelImageVisual::StopBehavior::Type stopBehavior;
     DevelImageVisual::LoopingMode::Type  loopingMode;
@@ -139,13 +146,19 @@ public:
   void SetRenderer(Renderer renderer);
 
   /**
-   * @brief Request to load the animation file.
+   * @brief Requests to load the animation file.
    *
    * @param[in] url The url of the vector animation file
    */
   void RequestLoad(const std::string& url);
 
   /**
+   * @brief Queries whether loading is requested.
+   * @return True if loading is requested.
+   */
+  bool IsLoadRequested() const;
+
+  /**
    * @brief Sets data to specify animation playback.
    * @param[in] data The animation data
    */
index 7e505c9..c6dbdb6 100644 (file)
@@ -85,7 +85,9 @@ void VectorAnimationThread::AddTask(VectorAnimationTaskPtr task)
 {
   ConditionalWait::ScopedLock lock(mConditionalWait);
 
-  if(mAnimationTasks.end() == std::find(mAnimationTasks.begin(), mAnimationTasks.end(), task))
+  // Find if the task is already in the list except loading task
+  auto iter = std::find_if(mAnimationTasks.begin(), mAnimationTasks.end(), [task](VectorAnimationTaskPtr& element) { return (element == task && !element->IsLoadRequested()); });
+  if(iter == mAnimationTasks.end())
   {
     auto currentTime = task->CalculateNextFrameTime(true); // Rasterize as soon as possible
 
index aa205cf..14e1ce3 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/images/pixel-data-devel.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/rendering/texture-devel.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
 #include <dali/integration-api/debug.h>
 #include <string.h>
@@ -569,8 +570,8 @@ void TextVisual::UpdateRenderer()
       const bool markupStrikethroughEnabled = markupProcessorEnabled && mController->GetTextModel()->IsMarkupStrikethroughSet();
       const bool underlineEnabled           = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
       const bool strikethroughEnabled       = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
-      const bool styleEnabled   = (shadowEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled);
-      const bool isOverlayStyle = underlineEnabled || strikethroughEnabled;
+      const bool styleEnabled               = (shadowEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled);
+      const bool isOverlayStyle             = underlineEnabled || strikethroughEnabled;
 
       AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
 
@@ -592,53 +593,47 @@ void TextVisual::AddTexture(TextureSet& textureSet, PixelData& data, Sampler& sa
   textureSet.SetSampler(textureSetIndex, sampler);
 }
 
-PixelData TextVisual::ConvertToPixelData(unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat)
+void TextVisual::AddTilingTexture(TextureSet& textureSet, TilingInfo& tilingInfo, PixelData& data, Sampler& sampler, unsigned int textureSetIndex)
 {
-  int            bpp        = Pixel::GetBytesPerPixel(textPixelFormat);
-  unsigned int   bufferSize = width * height * bpp;
-  unsigned char* dstBuffer  = static_cast<unsigned char*>(malloc(bufferSize));
-  memcpy(dstBuffer, buffer + offsetPosition * bpp, bufferSize);
-  PixelData pixelData = Dali::PixelData::New(dstBuffer,
-                                             bufferSize,
-                                             width,
-                                             height,
-                                             textPixelFormat,
-                                             Dali::PixelData::FREE);
-  return pixelData;
+  Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D,
+                                 tilingInfo.textPixelFormat,
+                                 tilingInfo.width,
+                                 tilingInfo.height);
+  DevelTexture::UploadSubPixelData(texture, data, 0u, tilingInfo.offsetHeight, tilingInfo.width, tilingInfo.height);
+
+  textureSet.SetTexture(textureSetIndex, texture);
+  textureSet.SetSampler(textureSetIndex, sampler);
 }
 
 void TextVisual::CreateTextureSet(TilingInfo& info, VisualRenderer& renderer, Sampler& sampler)
 {
-  TextureSet   textureSet      = TextureSet::New();
-  unsigned int textureSetIndex = 0u;
+  TextureSet textureSet      = TextureSet::New();
+  uint32_t   textureSetIndex = 0u;
 
   // Convert the buffer to pixel data to make it a texture.
 
-  if(info.textBuffer)
+  if(info.textPixelData)
   {
-    PixelData data = ConvertToPixelData(info.textBuffer, info.width, info.height, info.offsetPosition, info.textPixelFormat);
-    AddTexture(textureSet, data, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.textPixelData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(mTextShaderFeatureCache.IsEnabledStyle() && info.styleBuffer)
+  if(mTextShaderFeatureCache.IsEnabledStyle() && info.stylePixelData)
   {
-    PixelData styleData = ConvertToPixelData(info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888);
-    AddTexture(textureSet, styleData, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.stylePixelData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(mTextShaderFeatureCache.IsEnabledOverlay() && info.overlayStyleBuffer)
+  if(mTextShaderFeatureCache.IsEnabledOverlay() && info.overlayStylePixelData)
   {
-    PixelData overlayStyleData = ConvertToPixelData(info.overlayStyleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888);
-    AddTexture(textureSet, overlayStyleData, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.overlayStylePixelData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
 
-  if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor() && info.maskBuffer)
+  if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor() && info.maskPixelData)
   {
-    PixelData maskData = ConvertToPixelData(info.maskBuffer, info.width, info.height, info.offsetPosition, Pixel::L8);
-    AddTexture(textureSet, maskData, sampler, textureSetIndex);
+    AddTilingTexture(textureSet, info, info.maskPixelData, sampler, textureSetIndex);
+    ++textureSetIndex;
   }
 
   renderer.SetTextures(textureSet);
@@ -652,7 +647,7 @@ void TextVisual::CreateTextureSet(TilingInfo& info, VisualRenderer& renderer, Sa
 
   // Set size and offset for the tiling.
   renderer.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(info.width, info.height));
-  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, Vector2(info.offSet.x, info.offSet.y));
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, info.transformOffset);
   renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
   renderer.RegisterProperty("uHasMultipleTextColors", static_cast<float>(mTextShaderFeatureCache.IsEnabledMultiColor()));
 
@@ -702,32 +697,25 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     // Set information for creating textures.
     TilingInfo info(verifiedWidth, maxTextureSize, textPixelFormat);
 
-    // Get the buffer of text.
-    Dali::DevelPixelData::PixelDataBuffer textPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(data);
-    info.textBuffer                                     = textPixelData.buffer;
+    // Get the pixel data of text.
+    info.textPixelData = data;
 
     if(mTextShaderFeatureCache.IsEnabledStyle())
     {
       // Create RGBA texture for all the text styles (without the text itself)
-      PixelData                             styleData      = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
-      Dali::DevelPixelData::PixelDataBuffer stylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(styleData);
-      info.styleBuffer                                     = stylePixelData.buffer;
+      info.stylePixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
     }
 
     if(mTextShaderFeatureCache.IsEnabledOverlay())
     {
       // Create RGBA texture for all the overlay styles
-      PixelData                             overlayStyleData      = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888);
-      Dali::DevelPixelData::PixelDataBuffer overlayStylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(overlayStyleData);
-      info.overlayStyleBuffer                                     = overlayStylePixelData.buffer;
+      info.overlayStylePixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888);
     }
 
     if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor())
     {
       // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
-      PixelData                             maskData      = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8);
-      Dali::DevelPixelData::PixelDataBuffer maskPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(maskData);
-      info.maskBuffer                                     = maskPixelData.buffer;
+      info.maskPixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8);
     }
 
     // Get the current offset for recalculate the offset when tiling.
@@ -736,7 +724,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     Property::Value* offsetValue = retMap.Find(Dali::Toolkit::Visual::Transform::Property::OFFSET);
     if(offsetValue)
     {
-      offsetValue->Get(info.offSet);
+      offsetValue->Get(info.transformOffset);
     }
 
     // Create a textureset in the default renderer.
@@ -746,18 +734,17 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
 
     Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
 
-    int offsetPosition = verifiedWidth * maxTextureSize;
     // Create a renderer by cutting maxTextureSize.
     while(verifiedHeight > 0)
     {
       VisualRenderer tilingRenderer = VisualRenderer::New(geometry, shader);
       tilingRenderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT);
       // New offset position of buffer for tiling.
-      info.offsetPosition += offsetPosition;
+      info.offsetHeight += maxTextureSize;
       // New height for tiling.
       info.height = (verifiedHeight - maxTextureSize) > 0 ? maxTextureSize : verifiedHeight;
       // New offset for tiling.
-      info.offSet.y += maxTextureSize;
+      info.transformOffset.y += maxTextureSize;
       // Create a textureset int the new tiling renderer.
       CreateTextureSet(info, tilingRenderer, sampler);
 
@@ -820,9 +807,7 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size)
   // Create a texture for the text without any styles
   PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
 
-  // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
-  // In that case, create a texture. TODO: should tile the text.
-  unsigned int textureSetIndex = 0u;
+  uint32_t textureSetIndex = 0u;
   AddTexture(textureSet, data, sampler, textureSetIndex);
   ++textureSetIndex;
 
index c81fbce..1b1930d 100644 (file)
@@ -194,47 +194,31 @@ protected:
 private:
   struct TilingInfo
   {
-    unsigned char* textBuffer;
-    unsigned char* styleBuffer;
-    unsigned char* overlayStyleBuffer;
-    unsigned char* maskBuffer;
-    int            width;
-    int            height;
-    Pixel::Format  textPixelFormat;
-    int            offsetPosition;
-    Vector2        offSet;
-
-    TilingInfo(int width, int height, Pixel::Format textPixelFormat)
-    : textBuffer(NULL),
-      styleBuffer(NULL),
-      overlayStyleBuffer(NULL),
-      maskBuffer(NULL),
+    PixelData     textPixelData;
+    PixelData     stylePixelData;
+    PixelData     overlayStylePixelData;
+    PixelData     maskPixelData;
+    int32_t       width;
+    int32_t       height;
+    Pixel::Format textPixelFormat;
+    uint32_t      offsetHeight;
+    Vector2       transformOffset;
+
+    TilingInfo(int32_t width, int32_t height, Pixel::Format textPixelFormat)
+    : textPixelData(),
+      stylePixelData(),
+      overlayStylePixelData(),
+      maskPixelData(),
       width(width),
       height(height),
       textPixelFormat(textPixelFormat),
-      offsetPosition(0),
-      offSet(0.f, 0.f)
+      offsetHeight(0u),
+      transformOffset(0.f, 0.f)
     {
     }
 
     ~TilingInfo()
     {
-      if(textBuffer)
-      {
-        free(textBuffer);
-      }
-      if(styleBuffer)
-      {
-        free(styleBuffer);
-      }
-      if(overlayStyleBuffer)
-      {
-        free(overlayStyleBuffer);
-      }
-      if(maskBuffer)
-      {
-        free(maskBuffer);
-      }
     }
   };
 
@@ -260,21 +244,21 @@ private:
   /**
    * @brief Create a texture in textureSet and add it.
    * @param[in] textureSet The textureSet to which the texture will be added.
-   * @param[in] data The PixelData to be uploaded to texture
+   * @param[in] data The PixelData to be uploaded to texture.
    * @param[in] sampler The sampler.
    * @param[in] textureSetIndex The Index of TextureSet.
    */
   void AddTexture(TextureSet& textureSet, PixelData& data, Sampler& sampler, unsigned int textureSetIndex);
 
   /**
-   * @brief Convert the buffer to pixelData.
-   * @param[in] buffer The Buffer to be converted to pixelData.
-   * @param[in] width The width of pixel data.
-   * @param[in] height The height of pixel data.
-   * @param[in] offsetPosition The The buffer's start position.
-   * @param[in] textPixelFormat The PixelForma of text.
+   * @brief Create a texture in textureSet and add it.
+   * @param[in] textureSet The textureSet to which the texture will be added.
+   * @param[in] tilingInfo The tiling infomation to be uploaded to texture.
+   * @param[in] data The PixelData to be uploaded to texture.
+   * @param[in] sampler The sampler.
+   * @param[in] textureSetIndex The Index of TextureSet.
    */
-  PixelData ConvertToPixelData(unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat);
+  void AddTilingTexture(TextureSet& textureSet, TilingInfo& tilingInfo, PixelData& data, Sampler& sampler, unsigned int textureSetIndex);
 
   /**
    * @brief Create the text's texture. It will use cached shader feature for text visual.
index 99b6c38..ce78b7e 100644 (file)
@@ -517,6 +517,11 @@ void Visual::Base::DoAction(const Property::Index actionId, const Property::Valu
   }
 }
 
+void Visual::Base::DoActionExtension(const Dali::Property::Index actionId, const Dali::Any attributes)
+{
+  OnDoActionExtension(actionId, attributes);
+}
+
 void Visual::Base::SetDepthIndex(int index)
 {
   mImpl->mDepthIndex = index;
@@ -698,6 +703,11 @@ void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Va
   // May be overriden by derived class
 }
 
+void Visual::Base::OnDoActionExtension(const Property::Index actionId, const Dali::Any attributes)
+{
+  // May be overriden by derived class
+}
+
 void Visual::Base::RegisterMixColor()
 {
   if(mImpl->mRenderer)
index bdcb193..7ebf239 100644 (file)
@@ -100,6 +100,14 @@ public:
   void DoAction(const Dali::Property::Index actionId, const Dali::Property::Value attributes);
 
   /**
+   * @brief Performs an action on the visual with the given action id and attributes.
+   *
+   * @param[in] actionId The id of the action to perform this API only takes an Index
+   * @param[in] attributes The list of attributes for the action. ( optional for this data structure to have content )
+   */
+  void DoActionExtension(const Dali::Property::Index actionId, const Dali::Any attributes);
+
+  /**
    * @copydoc Toolkit::Visual::Base::GetHeightForWidth
    */
   virtual float GetHeightForWidth(float width);
@@ -363,6 +371,14 @@ protected:
   virtual void OnDoAction(const Property::Index actionId, const Property::Value& attributes);
 
   /**
+   * @brief Called by DoActionExtension() allowing sub classes to do the given action.
+   *
+   * @param[in] actionId The action to perform
+   * @param[in] attributes The list of attributes for the action. ( optional for this data structure to have content )
+   */
+  virtual void OnDoActionExtension(const Property::Index actionId, Dali::Any attributes);
+
+  /**
    * @brief Update the shader when some properties are changed.
    */
   virtual void UpdateShader()