Merge "Remove BaseHandle / BaseObject TypeTraits is trivialgit" into devel/master
authorEunki Hong <eunkiki.hong@samsung.com>
Wed, 17 Apr 2024 06:36:26 +0000 (06:36 +0000)
committerGerrit Code Review <gerrit@review>
Wed, 17 Apr 2024 06:36:26 +0000 (06:36 +0000)
14 files changed:
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Accessible.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
dali-toolkit/devel-api/controls/control-accessible.cpp
dali-toolkit/devel-api/visuals/image-visual-properties-devel.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/animated-vector-image/vector-animation-thread.h
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h

index f76c4a0..eee08a7 100644 (file)
 // test harness headers before dali headers.
 #include <dali-toolkit-test-suite-utils.h>
 
-#include <dali.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali.h>
 
-#include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
+#include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/atspi-interfaces/accessible.h>
 
 #include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h>
@@ -45,10 +46,10 @@ int utcDaliAccessibilityCheckBoxButtonGetStates(void)
   ToolkitTestApplication application;
 
   auto check_box_button = Toolkit::CheckBoxButton::New();
-  auto q = Dali::Accessibility::Accessible::Get( check_box_button );
-  DALI_TEST_CHECK( q );
+  auto q                = Dali::Accessibility::Accessible::Get(check_box_button);
+  DALI_TEST_CHECK(q);
   auto states = q->GetStates();
-  DALI_TEST_EQUALS( (int) states[ Dali::Accessibility::State::SELECTABLE ], (int) true, TEST_LOCATION );
+  DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SELECTABLE], (int)true, TEST_LOCATION);
 
   END_TEST;
 }
@@ -60,9 +61,9 @@ int utcDaliAccessibilityCheckLabelText(void)
   auto check_box_button = Toolkit::CheckBoxButton::New();
   //check_box_button.SetLabelText( "button" );
   check_box_button.SetProperty(Toolkit::Button::Property::LABEL, "button");
-  auto q = Dali::Accessibility::Accessible::Get( check_box_button );
-  DALI_TEST_CHECK( q );
-  DALI_TEST_EQUALS( q->GetName(), "button", TEST_LOCATION );
+  auto q = Dali::Accessibility::Accessible::Get(check_box_button);
+  DALI_TEST_CHECK(q);
+  DALI_TEST_EQUALS(q->GetName(), "button", TEST_LOCATION);
 
   END_TEST;
 }
@@ -77,7 +78,7 @@ int UtcDaliAccessibilityCheckShowingState(void)
   parentButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
   parentButton.SetProperty(Actor::Property::POSITION, Dali::Vector2(0.0f, 0.0f));
   parentButton.SetProperty(Actor::Property::SIZE, Dali::Vector2(200.0f, 200.0f));
-  application.GetScene().Add( parentButton );
+  application.GetScene().Add(parentButton);
 
   // Toatally inside of parent
   auto buttonA = Toolkit::PushButton::New();
@@ -99,7 +100,7 @@ int UtcDaliAccessibilityCheckShowingState(void)
   auto buttonC = Toolkit::PushButton::New();
   buttonC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
   buttonC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
-  buttonC.SetProperty(Actor::Property::POSITION, Dali::Vector2(100.0f,100.0f));
+  buttonC.SetProperty(Actor::Property::POSITION, Dali::Vector2(100.0f, 100.0f));
   buttonC.SetProperty(Actor::Property::SIZE, Dali::Vector2(200.0f, 200.0f));
   parentButton.Add(buttonC);
 
@@ -109,17 +110,17 @@ int UtcDaliAccessibilityCheckShowingState(void)
   auto q = Dali::Accessibility::Accessible::Get(buttonA);
   DALI_TEST_CHECK(q);
   auto states = q->GetStates();
-  DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) true, TEST_LOCATION);
+  DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)true, TEST_LOCATION);
 
   q = Dali::Accessibility::Accessible::Get(buttonB);
   DALI_TEST_CHECK(q);
   states = q->GetStates();
-  DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) true, TEST_LOCATION);
+  DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)true, TEST_LOCATION);
 
   q = Dali::Accessibility::Accessible::Get(buttonC);
   DALI_TEST_CHECK(q);
   states = q->GetStates();
-  DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) true, TEST_LOCATION);
+  DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)true, TEST_LOCATION);
 
   // Make SHOWING object invisible
   buttonC.SetProperty(Actor::Property::VISIBLE, false);
@@ -128,7 +129,7 @@ int UtcDaliAccessibilityCheckShowingState(void)
   application.Render(16);
 
   states = q->GetStates();
-  DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) false, TEST_LOCATION);
+  DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)false, TEST_LOCATION);
 
   // Make SHOWING parent invisible
   parentButton.SetProperty(Actor::Property::VISIBLE, false);
@@ -139,7 +140,7 @@ int UtcDaliAccessibilityCheckShowingState(void)
   q = Dali::Accessibility::Accessible::Get(buttonA);
   DALI_TEST_CHECK(q);
   states = q->GetStates();
-  DALI_TEST_EQUALS((int) states[Dali::Accessibility::State::SHOWING], (int) false, TEST_LOCATION);
+  DALI_TEST_EQUALS((int)states[Dali::Accessibility::State::SHOWING], (int)false, TEST_LOCATION);
 
   END_TEST;
 }
@@ -206,3 +207,70 @@ int utcDaliAutomationId(void)
 
   END_TEST;
 }
+
+int utcDaliImgSrc(void)
+{
+  ToolkitTestApplication application;
+  const std::string      imageSrcKey = "imgSrc";
+  // Check that imgSrc is NOT added for non-image view w/ no additional property
+  {
+    const auto checkBoxButton    = Toolkit::CheckBoxButton::New();
+    const auto controlAccessible = Dali::Accessibility::Accessible::Get(checkBoxButton);
+    auto       attributes        = controlAccessible->GetAttributes();
+    DALI_TEST_CHECK(attributes.find(imageSrcKey) == attributes.end());
+  }
+
+  // Check that imgSrc is NOT added for non-image view w/ additional properties
+  {
+    const auto textLabel         = Toolkit::TextLabel::New("Hello");
+    const auto controlAccessible = Dali::Accessibility::Accessible::Get(textLabel);
+    auto       attributes        = controlAccessible->GetAttributes();
+    DALI_TEST_CHECK(attributes.find(imageSrcKey) == attributes.end());
+  }
+
+  // Check that imgSrc is added for image view w/ Url
+  {
+    const std::string imagePath         = "gallery-small-1.jpg";
+    const auto        imageView         = Toolkit::ImageView::New(imagePath);
+    const auto        controlAccessible = Dali::Accessibility::Accessible::Get(imageView);
+    auto              attributes        = controlAccessible->GetAttributes();
+    DALI_TEST_CHECK(attributes.find(imageSrcKey) != attributes.end());
+    DALI_TEST_EQUALS(attributes[imageSrcKey], imagePath, TEST_LOCATION);
+  }
+
+  // Check that imgSrc is added for image view w/ imageMap; single url case
+  {
+    const std::string imagePathForImageMap = "icon-edit.png";
+    Property::Map     imageMap;
+    imageMap[Toolkit::ImageVisual::Property::URL]            = imagePathForImageMap;
+    imageMap[Toolkit::ImageVisual::Property::RELEASE_POLICY] = Toolkit::ImageVisual::ReleasePolicy::DETACHED;
+
+    auto imageView = Toolkit::ImageView::New();
+    imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, imageMap);
+
+    const auto controlAccessible = Dali::Accessibility::Accessible::Get(imageView);
+    auto       attributes        = controlAccessible->GetAttributes();
+    DALI_TEST_CHECK(attributes.find(imageSrcKey) != attributes.end());
+    DALI_TEST_EQUALS(attributes[imageSrcKey], imagePathForImageMap, TEST_LOCATION);
+  }
+
+  // Check that imgSrc is added for image view w/ imageMap; url array returns first element
+  {
+    const std::string image1 = "application-icon-20.png";
+    const std::string image2 = "application-icon-21.png";
+    Property::Map     imageMap;
+    Property::Array   urls{image1, image2};
+    imageMap[Toolkit::ImageVisual::Property::URL]            = urls;
+    imageMap[Toolkit::ImageVisual::Property::RELEASE_POLICY] = Toolkit::ImageVisual::ReleasePolicy::DETACHED;
+
+    auto imageView = Toolkit::ImageView::New();
+    imageView.SetProperty(Toolkit::ImageView::Property::IMAGE, imageMap);
+
+    const auto controlAccessible = Dali::Accessibility::Accessible::Get(imageView);
+    auto       attributes        = controlAccessible->GetAttributes();
+    DALI_TEST_CHECK(attributes.find(imageSrcKey) != attributes.end());
+    DALI_TEST_EQUALS(attributes[imageSrcKey], image1, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
index 49c344a..6a69f93 100644 (file)
@@ -71,6 +71,8 @@ public:
   void RemoveIdle(CallbackBase* callback);
   void RunIdles();
 
+  void RequestUpdateOnce();
+
   static Integration::Scene GetScene(Dali::Window window);
 
   Dali::RenderSurfaceInterface& GetSurface();
index 4d77310..40c73ae 100644 (file)
@@ -139,6 +139,19 @@ void Adaptor::RunIdles()
   mReturnCallbacks.Swap(reusedCallbacks);
 }
 
+void Adaptor::RequestUpdateOnce()
+{
+  if(mTestApplication)
+  {
+    auto scene = mTestApplication->GetScene();
+    if(scene)
+    {
+      tet_printf("Adaptor::RequestUpdateOnce()\n");
+      scene.KeepRendering(0.0f);
+    }
+  }
+}
+
 Dali::RenderSurfaceInterface& Adaptor::GetSurface()
 {
   DALI_ASSERT_ALWAYS(!mWindows.empty());
index 08921c9..55891b8 100644 (file)
@@ -69,6 +69,100 @@ void VisualEventSignal(Control control, Dali::Property::Index visualIndex, Dali:
   }
 }
 
+/**
+ * @brief Retry function to get playrange until expect values comes.
+ * @note This function might consume EventThreadTrigger.
+ *
+ * @param[in] dummyControl The control for test.
+ * @param[in] expectStartFrame Expect start frame.
+ * @param[in] expectEndFrame Expect end frame.
+ * @param[in] retrialFrames Retry required frame value list.
+ * @param[in] testLocation Location info of UTC. It will be used when UTC failed.
+ */
+void CheckAndRetryPlayRange(DummyControl dummyControl, int expectStartFrame, int expectEndFrame, std::vector<std::pair<int, int>> retrialFrames, const char* testLocation)
+{
+  int tryCount    = 0;
+  int tryCountMax = 25;
+  while(++tryCount <= tryCountMax)
+  {
+    Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+    Property::Value* value = resultMap.Find(DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY);
+    DALI_TEST_CHECK(value);
+
+    Property::Array* result = value->GetArray();
+    DALI_TEST_CHECK(result);
+    DALI_TEST_EQUALS(result->Count(), 2, TEST_LOCATION);
+
+    bool tryAgain = false;
+    for(auto& framePair : retrialFrames)
+    {
+      if(result->GetElementAt(0).Get<int>() == framePair.first && result->GetElementAt(1).Get<int>() == framePair.second)
+      {
+        tryAgain = true;
+        break;
+      }
+    }
+    if(tryAgain)
+    {
+      tet_printf("Retry to get value again! [%d]\n", tryCount);
+      // Dummy sleep 1 second.
+      Test::WaitForEventThreadTrigger(1, 1);
+      continue;
+    }
+
+    DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), expectStartFrame, testLocation);
+    DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), expectEndFrame, testLocation);
+    break;
+  }
+  DALI_TEST_CHECK(tryCount <= tryCountMax);
+}
+
+/**
+ * @brief Retry function to get current frame until expect values comes.
+ * @note This function might consume EventThreadTrigger.
+ *
+ * @param[in] dummyControl The control for test.
+ * @param[in] expectCurrentFrame Expect current frame.
+ * @param[in] retrialFrames Retry required frame value list.
+ * @param[in] testLocation Location info of UTC. It will be used when UTC failed.
+ */
+void CheckAndRetryCurrentFrame(DummyControl dummyControl, int expectCurrentFrame, std::vector<int> retrialFrames, const char* testLocation)
+{
+  int tryCount    = 0;
+  int tryCountMax = 25;
+  while(++tryCount <= tryCountMax)
+  {
+    Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+    Property::Value* value = resultMap.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER, Property::INTEGER);
+    DALI_TEST_CHECK(value);
+
+    int32_t result = value->Get<int32_t>();
+
+    bool tryAgain = false;
+    for(auto& frame : retrialFrames)
+    {
+      if(result == frame)
+      {
+        tryAgain = true;
+        break;
+      }
+    }
+    if(tryAgain)
+    {
+      tet_printf("Retry to get value again! [%d]\n", tryCount);
+      // Dummy sleep 1 second.
+      Test::WaitForEventThreadTrigger(1, 1);
+      continue;
+    }
+
+    DALI_TEST_EQUALS(result, expectCurrentFrame, testLocation);
+    break;
+  }
+  DALI_TEST_CHECK(tryCount <= tryCountMax);
+}
+
 } // namespace
 
 int UtcDaliVisualFactoryGetAnimatedVectorImageVisual01(void)
@@ -174,8 +268,17 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual03(void)
   // Trigger count is 2 - load & render a frame
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
+  // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+  // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+  // Consume it if required.
+  if(actor.GetRendererCount() == 0)
+  {
+    tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+    Test::WaitForEventThreadTrigger(1, 1);
+  }
+
   // renderer is added to actor
-  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
 
@@ -208,13 +311,14 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
     .Add("stopBehavior", DevelImageVisual::StopBehavior::FIRST_FRAME)
     .Add("loopingMode", DevelImageVisual::LoopingMode::AUTO_REVERSE)
     .Add("redrawInScalingDown", false)
+    .Add("enableFrameCache", false)
+    .Add("notifyAfterRasterization", false)
     .Add("cornerRadius", cornerRadius)
     .Add("borderlineWidth", borderlineWidth)
     .Add("borderlineColor", borderlineColor)
     .Add("borderlineOffset", borderlineOffset)
     .Add("desiredWidth", desiredWidth)
-    .Add("desiredHeight", desiredHeight)
-    .Add("useFixedCache", false);
+    .Add("desiredHeight", desiredHeight);
 
   Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
   DALI_TEST_CHECK(visual);
@@ -231,8 +335,17 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
   // Trigger count is 1 - render a frame
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
+  // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+  // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+  // Consume it if required.
+  if(actor.GetRendererCount() == 0)
+  {
+    tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+    Test::WaitForEventThreadTrigger(1, 1);
+  }
+
   // renderer is added to actor
-  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
 
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
@@ -270,6 +383,14 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<bool>() == false);
 
+  value = resultMap.Find(DevelImageVisual::Property::ENABLE_FRAME_CACHE, Property::BOOLEAN);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<bool>() == false);
+
+  value = resultMap.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, Property::BOOLEAN);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<bool>() == false);
+
   value = resultMap.Find(DevelVisual::Property::CORNER_RADIUS, Property::VECTOR4);
   DALI_TEST_CHECK(value);
   DALI_TEST_EQUALS(value->Get<Vector4>(), Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius), TEST_LOCATION);
@@ -395,6 +516,10 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<bool>() == false); // Check default value
 
+  value = resultMap.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, Property::BOOLEAN);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<bool>() == false); // Check default value
+
   value = resultMap.Find(DevelImageVisual::Property::REDRAW_IN_SCALING_DOWN, Property::BOOLEAN);
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<bool>() == true); // Check default value
@@ -703,7 +828,7 @@ int UtcDaliAnimatedVectorImageVisualLoopCount(void)
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
   // renderer is added to actor
-  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
 
@@ -747,8 +872,17 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
   // Trigger count is 2 - load & render a frame
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
+  // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+  // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+  // Consume it if required.
+  if(actor.GetRendererCount() == 0)
+  {
+    tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+    Test::WaitForEventThreadTrigger(1, 1);
+  }
+
   // renderer is added to actor
-  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
 
@@ -767,7 +901,7 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
   // Set invalid play range
   array.Clear();
   array.PushBack(1);
-  array.PushBack(100);
+  array.PushBack(totalFrameNumber + 100);
 
   attributes.Clear();
   attributes.Add(DevelImageVisual::Property::PLAY_RANGE, array);
@@ -781,15 +915,8 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
 
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
-  map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
-  value = map.Find(DevelImageVisual::Property::PLAY_RANGE);
-
-  result = value->GetArray();
-  result->GetElementAt(0).Get(resultStartFrame);
-  result->GetElementAt(1).Get(resultEndFrame);
-
-  DALI_TEST_EQUALS(resultStartFrame, 1, TEST_LOCATION);
-  DALI_TEST_EQUALS(resultEndFrame, totalFrameNumber - 1, TEST_LOCATION); // Should be clamped
+  // Should be clamped.
+  CheckAndRetryPlayRange(actor, 1, totalFrameNumber - 1, {{startFrame, endFrame}}, TEST_LOCATION);
 
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, Property::Map());
 
@@ -798,17 +925,14 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
 
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
 
-  // To make event trigger
-  actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
-
   application.SendNotification();
   application.Render();
 
+  // Jump to action when paused, will make one or more event trigger
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
-  map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
-  value = map.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER);
-  DALI_TEST_EQUALS(value->Get<int>(), 3, TEST_LOCATION);
+  // Test whether current frame is 3.
+  CheckAndRetryCurrentFrame(actor, 3, {0, 1}, TEST_LOCATION);
 
   array.Clear();
   array.PushBack(0);
@@ -819,23 +943,16 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes);
 
   // To make event trigger
-  actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
+  actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
 
   application.SendNotification();
   application.Render();
 
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
-  map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
-  value = map.Find(DevelImageVisual::Property::PLAY_RANGE);
-
-  result = value->GetArray();
-  result->GetElementAt(0).Get(resultStartFrame);
-  result->GetElementAt(1).Get(resultEndFrame);
-
-  DALI_TEST_EQUALS(0, resultStartFrame, TEST_LOCATION);
-  DALI_TEST_EQUALS(2, resultEndFrame, TEST_LOCATION);
+  CheckAndRetryPlayRange(actor, 0, 2, {{1, totalFrameNumber - 1}}, TEST_LOCATION);
 
+  map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
   value = map.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER);
   DALI_TEST_EQUALS(value->Get<int>(), 2, TEST_LOCATION); // CURRENT_FRAME_NUMBER should be changed also.
 
@@ -878,8 +995,17 @@ int UtcDaliAnimatedVectorImageVisualPlayRangeMarker(void)
   // Trigger count is 2 - load & render a frame
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
+  // There might be 1 event triggered if start frame is not 0, and render frame spend long time.
+  // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+  // Consume it if required.
+  if(actor.GetRendererCount() == 0)
+  {
+    tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+    Test::WaitForEventThreadTrigger(1, 1);
+  }
+
   // renderer is added to actor
-  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
 
@@ -1008,7 +1134,7 @@ int UtcDaliAnimatedVectorImageVisualMarkerInfo(void)
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
 
   // renderer is added to actor
-  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
   Renderer renderer = actor.GetRendererAt(0u);
   DALI_TEST_CHECK(renderer);
 
@@ -1100,10 +1226,10 @@ int UtcDaliAnimatedVectorImageVisualMarkerInfoFromInvalid(void)
   END_TEST;
 }
 
-int UtcDaliAnimatedVectorImageVisualUsedFixedCache(void)
+int UtcDaliAnimatedVectorImageVisualEnableFrameCache(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("UtcDaliAnimatedVectorImageVisualUsedFixedCache");
+  tet_infoline("UtcDaliAnimatedVectorImageVisualEnableFrameCache");
 
   Property::Map propertyMap;
   propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
@@ -1117,13 +1243,12 @@ int UtcDaliAnimatedVectorImageVisualUsedFixedCache(void)
   DummyControl      actor     = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
   dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
-  //actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
   application.GetScene().Add(actor);
 
   application.SendNotification();
   application.Render();
 
-  // Trigger count is 1 - render a frame
+  // Trigger count is 1 - load
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   Vector2 controlSize(200.f, 200.f);
@@ -1132,7 +1257,7 @@ int UtcDaliAnimatedVectorImageVisualUsedFixedCache(void)
   application.SendNotification();
   application.Render();
 
-  // Trigger count is 1 - load
+  // Trigger count is 1 - render a frame
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   // renderer is added to actor
@@ -1147,10 +1272,10 @@ int UtcDaliAnimatedVectorImageVisualUsedFixedCache(void)
   END_TEST;
 }
 
-int UtcDaliAnimatedVectorImageVisualUsedFixedCacheFailed(void)
+int UtcDaliAnimatedVectorImageVisualEnableFrameCacheFailed(void)
 {
   ToolkitTestApplication application;
-  tet_infoline("UtcDaliAnimatedVectorImageVisualUsedFixedCacheFailed");
+  tet_infoline("UtcDaliAnimatedVectorImageVisualEnableFrameCacheFailed");
 
   Property::Map propertyMap;
   propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
@@ -1194,6 +1319,100 @@ int UtcDaliAnimatedVectorImageVisualUsedFixedCacheFailed(void)
   END_TEST;
 }
 
+int UtcDaliAnimatedVectorImageVisualNotifyAfterRasterization(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedVectorImageVisualNotifyAfterRasterization");
+
+  Property::Map propertyMap;
+  propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+    .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
+    .Add(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, true)
+    .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+  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);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - load
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  Vector2 controlSize(200.f, 200.f);
+  actor.SetProperty(Actor::Property::SIZE, controlSize);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  // Play animation
+  Property::Map attributes;
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+
+  application.SendNotification();
+  application.Render();
+
+  // There might be 1 event triggered if render frame spend long time.
+  // if ForceRenderOnce triggered before render complete, renderer count could be zero.
+  // Consume it if required.
+  if(actor.GetRendererCount() == 0)
+  {
+    tet_printf("Warning! render frame trigger not comes yet. Let we wait one more time.\n");
+    Test::WaitForEventThreadTrigger(1, 1);
+  }
+
+  // renderer is added to actor
+  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+  Renderer renderer = actor.GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+
+  // Check renderer behavior
+  DALI_TEST_CHECK(renderer.GetProperty<int>(DevelRenderer::Property::RENDERING_BEHAVIOR) == DevelRenderer::Rendering::IF_REQUIRED);
+
+  Property::Map    map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+  Property::Value* value = map.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION);
+  DALI_TEST_CHECK(value->Get<bool>() == true);
+
+  propertyMap.Clear();
+  propertyMap.Add(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, false);
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
+  application.SendNotification();
+  application.Render();
+
+  // Check renderer behavior again
+  DALI_TEST_CHECK(renderer.GetProperty<int>(DevelRenderer::Property::RENDERING_BEHAVIOR) == DevelRenderer::Rendering::CONTINUOUSLY);
+
+  map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+  value = map.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION);
+  DALI_TEST_CHECK(value->Get<bool>() == false);
+
+  propertyMap.Clear();
+  propertyMap.Add(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, true);
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, propertyMap);
+
+  application.SendNotification();
+  application.Render();
+
+  // Check renderer behavior again
+  DALI_TEST_CHECK(renderer.GetProperty<int>(DevelRenderer::Property::RENDERING_BEHAVIOR) == DevelRenderer::Rendering::IF_REQUIRED);
+
+  map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+  value = map.Find(DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION);
+  DALI_TEST_CHECK(value->Get<bool>() == true);
+
+  END_TEST;
+}
+
 int UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal(void)
 {
   ToolkitTestApplication application;
@@ -1278,12 +1497,10 @@ int UtcDaliAnimatedVectorImageVisualJumpTo(void)
 
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 2);
 
-  // To make event trigger
-  actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
-
   application.SendNotification();
   application.Render();
 
+  // Trigger count is 1 - Jump to during stopped
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   Property::Map    map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
@@ -1303,7 +1520,7 @@ int UtcDaliAnimatedVectorImageVisualJumpTo(void)
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
 
   // To make event trigger
-  actor.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
+  actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
 
   application.SendNotification();
   application.Render();
@@ -1334,19 +1551,16 @@ int UtcDaliAnimatedVectorImageVisualJumpTo(void)
 
   // Wait for animation finish
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
-  // EventThread will be triggered after animation finished (For render forcibly).
-  // TODO : Is this logic will works well on server-side?
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  // Note : AnimationFinished will occure force-render, and it might required another trigger. Test one more trigger now.
+  Test::WaitForEventThreadTrigger(1, 1);
 
   // Jump to 3
   DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3);
 
-  // To make event trigger
-  actor.SetProperty(Actor::Property::SIZE, Vector2(10.0f, 10.0f));
-
   application.SendNotification();
   application.Render();
 
+  // Trigger count is 1 - Jump to during stopped.
   DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
 
   map   = actor.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
@@ -1420,8 +1634,8 @@ int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
   Property::Array* result = value->GetArray();
   DALI_TEST_CHECK(result);
 
-  DALI_TEST_CHECK(result->GetElementAt(0).Get<int>() == startFrame);
-  DALI_TEST_CHECK(result->GetElementAt(1).Get<int>() == endFrame);
+  DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), startFrame, TEST_LOCATION);
+  DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), endFrame, TEST_LOCATION);
 
   playRange.Clear();
   playRange.PushBack(0);
@@ -1449,8 +1663,8 @@ int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
   result = value->GetArray();
   DALI_TEST_CHECK(result);
 
-  DALI_TEST_CHECK(result->GetElementAt(0).Get<int>() == 0);
-  DALI_TEST_CHECK(result->GetElementAt(1).Get<int>() == 2);
+  // Ensure that vector data sended well.
+  CheckAndRetryPlayRange(actor, 0, 2, {{startFrame, endFrame}}, TEST_LOCATION);
 
   attributes.Clear();
 
@@ -1476,8 +1690,8 @@ int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
   result = value->GetArray();
   DALI_TEST_CHECK(result);
 
-  DALI_TEST_CHECK(result->GetElementAt(0).Get<int>() == startFrame);
-  DALI_TEST_CHECK(result->GetElementAt(1).Get<int>() == endFrame);
+  // Ensure that vector data sended well.
+  CheckAndRetryPlayRange(actor, startFrame, endFrame, {{0, 2}}, TEST_LOCATION);
 
   // Play and update property
   attributes.Clear();
@@ -2391,45 +2605,6 @@ int UtcDaliAnimatedVectorImageVisualFlushAction(void)
 
   application.GetScene().Add(dummyControl);
 
-  // Retry function to get playrange until expect values comes.
-  auto CheckAndRetryPlayRange = [&](int expectStartFrame, int expectEndFrame, std::vector<std::pair<int, int>> retrialFrames) {
-    int tryCount    = 0;
-    int tryCountMax = 30;
-    while(++tryCount <= tryCountMax)
-    {
-      Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
-
-      Property::Value* value = resultMap.Find(DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY);
-      DALI_TEST_CHECK(value);
-
-      Property::Array* result = value->GetArray();
-      DALI_TEST_CHECK(result);
-      DALI_TEST_EQUALS(result->Count(), 2, TEST_LOCATION);
-
-      bool tryAgain = false;
-      for(auto& framePair : retrialFrames)
-      {
-        if(result->GetElementAt(0).Get<int>() == framePair.first && result->GetElementAt(1).Get<int>() == framePair.second)
-        {
-          tryAgain = true;
-          break;
-        }
-      }
-      if(tryAgain)
-      {
-        tet_printf("Retry to get value again! [%d]\n", tryCount);
-        // Dummy sleep 1 second.
-        Test::WaitForEventThreadTrigger(1, 1);
-        continue;
-      }
-
-      DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), expectStartFrame, TEST_LOCATION);
-      DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), expectEndFrame, TEST_LOCATION);
-      break;
-    }
-    DALI_TEST_CHECK(tryCount <= tryCountMax);
-  };
-
   tet_printf("Pause lottie first.\n");
 
   Property::Map attributes;
@@ -2448,7 +2623,7 @@ int UtcDaliAnimatedVectorImageVisualFlushAction(void)
   } while(totalFrameCount == 0);
 
   // Ensure that vector data sended well.
-  CheckAndRetryPlayRange(startFrame, endFrame, {{0, 0}, {0, totalFrameCount - 1}});
+  CheckAndRetryPlayRange(dummyControl, startFrame, endFrame, {{0, 0}, {0, totalFrameCount - 1}}, TEST_LOCATION);
 
   resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
 
@@ -2493,7 +2668,7 @@ int UtcDaliAnimatedVectorImageVisualFlushAction(void)
   application.Render(16);
 
   // Ensure that vector data sended well.
-  CheckAndRetryPlayRange(changedStartFrame2, changedEndFrame2, {{changedStartFrame1, changedEndFrame1}, {startFrame, endFrame}});
+  CheckAndRetryPlayRange(dummyControl, changedStartFrame2, changedEndFrame2, {{changedStartFrame1, changedEndFrame1}, {startFrame, endFrame}}, TEST_LOCATION);
 
   resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
 
index 8788ade..4aef1f0 100644 (file)
 
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/public-api/object/property-map.h>
 #include <dali/public-api/object/type-info.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/visuals/image/image-visual.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
@@ -39,7 +41,9 @@ namespace Dali::Toolkit::DevelControl
 {
 namespace
 {
-static std::string GetLocaleText(std::string string, const char* domain = "dali-toolkit")
+constexpr const char* ATTR_IMG_SRC_KEY = "imgSrc";
+
+std::string GetLocaleText(std::string string, const char* domain = "dali-toolkit")
 {
 #ifdef DGETTEXT_ENABLED
   /*TODO: currently non-localized string is used as a key for translation lookup. In case the lookup key formatting is forced
@@ -50,7 +54,7 @@ static std::string GetLocaleText(std::string string, const char* domain = "dali-
 #endif
 }
 
-static Dali::Actor CreateHighlightIndicatorActor()
+Dali::Actor CreateHighlightIndicatorActor()
 {
   std::string focusBorderImagePath(AssetManager::GetDaliImagePath());
   focusBorderImagePath += "/keyboard_focus.9.png";
@@ -65,6 +69,45 @@ static Dali::Actor CreateHighlightIndicatorActor()
 
   return actor;
 }
+
+std::string FetchImageSrcFromMap(const Dali::Property::Map& imageMap)
+{
+  auto urlVal = imageMap.Find(Toolkit::ImageVisual::Property::URL);
+  if(urlVal)
+  {
+    if(urlVal->GetType() == Dali::Property::STRING)
+    {
+      return urlVal->Get<std::string>();
+    }
+    else if(urlVal->GetType() == Dali::Property::ARRAY)
+    {
+      auto urlArray = urlVal->GetArray();
+      if(urlArray && !urlArray->Empty())
+      {
+        // Returns first element if url is an array
+        return (*urlArray)[0].Get<std::string>();
+      }
+    }
+  }
+  return {};
+}
+
+std::string FetchImageSrc(const Toolkit::ImageView& imageView)
+{
+  const auto imageUrl = imageView.GetProperty<std::string>(Toolkit::ImageView::Property::IMAGE);
+  if(!imageUrl.empty())
+  {
+    return imageUrl;
+  }
+
+  const auto imageMap = imageView.GetProperty<Dali::Property::Map>(Toolkit::ImageView::Property::IMAGE);
+  if(!imageMap.Empty())
+  {
+    return FetchImageSrcFromMap(imageMap);
+  }
+  return {};
+}
+
 } // unnamed namespace
 
 ControlAccessible::ControlAccessible(Dali::Actor self)
@@ -235,6 +278,15 @@ Dali::Accessibility::Attributes ControlAccessible::GetAttributes() const
     result.emplace(automationIdKey, std::move(automationId));
   }
 
+  if(auto imageView = Toolkit::ImageView::DownCast(Self()))
+  {
+    auto imageSrc = FetchImageSrc(imageView);
+    if(!imageSrc.empty())
+    {
+      result.emplace(ATTR_IMG_SRC_KEY, std::move(imageSrc));
+    }
+  }
+
   // Add "class" if not present already
   if(result.find(classKey) == result.end())
   {
index a5e135c..90e868e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
 
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -193,13 +193,24 @@ enum Type
 
   /**
    * @brief Whether to AnimatedVectorImageVisual fixed cache or not.
-   * @details Name "EnableFrameCache", type Property::BOOLEAN.
+   * @details Name "enableFrameCache", type Property::BOOLEAN.
    * If this property is true, AnimatedVectorImageVisual enable frame cache for loading and keeps loaded frame
    * until the visual is removed. It reduces CPU cost when the animated image will be looping.
    * But it can spend a lot of memory if the resource has high resolution image or many frame count.
-   * @note It is used in the AnimatedImageVisual. The default is false
+   * @note It is used in the AnimatedVectorImageVisual. The default is false
    */
-  ENABLE_FRAME_CACHE = ORIENTATION_CORRECTION + 16
+  ENABLE_FRAME_CACHE = ORIENTATION_CORRECTION + 16,
+
+  /**
+   * @brief Whether notify AnimatedVectorImageVisual to render thread after every rasterization or not.
+   * @details Name "notifyAfterRasterization", type Property::BOOLEAN.
+   * If this property is true, AnimatedVectorImageVisual send notify to render thread after every rasterization.
+   * If false, AnimatedVectorImageVisual set Renderer's Behaviour as Continouly (mean, always update the render thread.)
+   *
+   * This flag is useful if given resource has low fps, so we don't need to render every frame.
+   * @note It is used in the AnimatedVectorImageVisual. The default is false.
+   */
+  NOTIFY_AFTER_RASTERIZATION = ORIENTATION_CORRECTION + 17
 };
 
 } //namespace Property
index b23f066..238de79 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/common/stage.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/math/math-utils.h>
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
@@ -103,7 +104,8 @@ AnimatedVectorImageVisual::AnimatedVectorImageVisual(VisualFactoryCache& factory
   mCoreShutdown(false),
   mRedrawInScalingDown(true),
   mEnableFrameCache(false),
-  mUseNativeImage(false)
+  mUseNativeImage(false),
+  mNotifyAfterRasterization(false)
 {
   // the rasterized image is with pre-multiplied alpha format
   mImpl->mFlags |= Visual::Base::Impl::IS_PREMULTIPLIED_ALPHA;
@@ -221,6 +223,7 @@ void AnimatedVectorImageVisual::DoCreatePropertyMap(Property::Map& map) const
   map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
   map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
   map.Insert(Toolkit::DevelImageVisual::Property::ENABLE_FRAME_CACHE, mEnableFrameCache);
+  map.Insert(Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, mNotifyAfterRasterization);
 }
 
 void AnimatedVectorImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
@@ -285,6 +288,10 @@ void AnimatedVectorImageVisual::DoSetProperties(const Property::Map& propertyMap
       {
         DoSetProperty(Toolkit::DevelImageVisual::Property::ENABLE_FRAME_CACHE, keyValue.second);
       }
+      else if(keyValue.first == NOTIFY_AFTER_RASTERIZATION)
+      {
+        DoSetProperty(Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION, keyValue.second);
+      }
     }
   }
 
@@ -404,6 +411,22 @@ void AnimatedVectorImageVisual::DoSetProperty(Property::Index index, const Prope
       }
       break;
     }
+
+    case Toolkit::DevelImageVisual::Property::NOTIFY_AFTER_RASTERIZATION:
+    {
+      bool notifyAfterRasterization = false;
+      if(value.Get(notifyAfterRasterization))
+      {
+        if(mNotifyAfterRasterization != notifyAfterRasterization)
+        {
+          mNotifyAfterRasterization = notifyAfterRasterization;
+
+          mAnimationData.notifyAfterRasterization = mNotifyAfterRasterization;
+          mAnimationData.resendFlag |= VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION;
+        }
+      }
+      break;
+    }
   }
 }
 
@@ -411,7 +434,6 @@ void AnimatedVectorImageVisual::OnInitialize(void)
 {
   mVectorAnimationTask->ResourceReadySignal().Connect(this, &AnimatedVectorImageVisual::OnResourceReady);
   mVectorAnimationTask->SetAnimationFinishedCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnAnimationFinished));
-  mVectorAnimationTask->SetForceRenderOnceCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnForceRendering));
 
   EncodedImageBuffer encodedImageBuffer;
 
@@ -719,20 +741,12 @@ void AnimatedVectorImageVisual::OnAnimationFinished(uint32_t playStateId)
     }
   }
 
-  if(mImpl->mRenderer)
+  if(!mNotifyAfterRasterization && mImpl->mRenderer)
   {
     mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
   }
 }
 
-void AnimatedVectorImageVisual::OnForceRendering(uint32_t playStateId)
-{
-  if(!mCoreShutdown)
-  {
-    Stage::GetCurrent().KeepRendering(0.0f); // Trigger event processing
-  }
-}
-
 void AnimatedVectorImageVisual::SendAnimationData()
 {
   if(mAnimationData.resendFlag)
@@ -746,14 +760,18 @@ void AnimatedVectorImageVisual::SendAnimationData()
     }
     mVectorAnimationTask->SetAnimationData(mAnimationData);
 
-    if(mImpl->mRenderer)
+    if(mImpl->mRenderer &&
+       ((mAnimationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE) ||
+        (mAnimationData.resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION)))
     {
-      if(mAnimationData.playState == DevelImageVisual::PlayState::PLAYING)
+      if(!mNotifyAfterRasterization && mPlayState == DevelImageVisual::PlayState::PLAYING)
       {
+        // Make rendering behaviour if we don't notify after rasterization, but animation playing.
         mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
       }
       else
       {
+        // Otherwise, notify will be sended after rasterization. Make behaviour as required.
         mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
       }
     }
index 7e7b04d..a1e7480 100644 (file)
@@ -188,13 +188,6 @@ private:
   void OnAnimationFinished(uint32_t playStateId);
 
   /**
-   * @brief Event callback from rasterize thread. This is called when we want to ensure rendering next frame.
-   *
-   * @param[in] argument Not using arguments
-   */
-  void OnForceRendering(uint32_t argument);
-
-  /**
    * @brief Send animation data to the rasterize thread.
    */
   void SendAnimationData();
@@ -267,6 +260,7 @@ private:
   bool mRedrawInScalingDown : 1;
   bool mEnableFrameCache : 1;
   bool mUseNativeImage : 1;
+  bool mNotifyAfterRasterization : 1;
 };
 
 } // namespace Internal
index 423d3fc..ac448c0 100644 (file)
@@ -108,6 +108,7 @@ VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
   mLayerInfoCached(false),
   mMarkerInfoCached(false),
   mEnableFrameCache(false),
+  mNotifyAfterRasterization(false),
   mSizeUpdated(false)
 {
   mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted);
@@ -139,11 +140,6 @@ void VectorAnimationTask::Finalize()
       mVectorAnimationThread.RemoveEventTriggerCallbacks(mAnimationFinishedCallback.get());
       mAnimationFinishedCallback.reset();
     }
-    if(mForceRenderOnceCallback)
-    {
-      mVectorAnimationThread.RemoveEventTriggerCallbacks(mForceRenderOnceCallback.get());
-      mForceRenderOnceCallback.reset();
-    }
     if(mLoadCompletedCallback)
     {
       mVectorAnimationThread.RemoveEventTriggerCallbacks(mLoadCompletedCallback.get());
@@ -395,12 +391,6 @@ void VectorAnimationTask::SetAnimationFinishedCallback(CallbackBase* callback)
   mAnimationFinishedCallback = std::unique_ptr<CallbackBase>(callback);
 }
 
-void VectorAnimationTask::SetForceRenderOnceCallback(CallbackBase* callback)
-{
-  Mutex::ScopedLock lock(mMutex);
-  mForceRenderOnceCallback = std::unique_ptr<CallbackBase>(callback);
-}
-
 void VectorAnimationTask::SetLoopCount(int32_t count)
 {
   if(mLoopCount != count)
@@ -747,13 +737,10 @@ bool VectorAnimationTask::Rasterize()
   }
 
   // Forcely trigger render once if need.
-  if(mNeedForceRenderOnceTrigger)
+  if(mNotifyAfterRasterization || mNeedForceRenderOnceTrigger)
   {
     Mutex::ScopedLock lock(mMutex);
-    if(mForceRenderOnceCallback)
-    {
-      mVectorAnimationThread.AddEventTriggerCallback(mForceRenderOnceCallback.get(), mAppliedPlayStateId);
-    }
+    mVectorAnimationThread.RequestForceRenderOnce();
     mNeedForceRenderOnceTrigger = false;
   }
 
@@ -891,6 +878,11 @@ void VectorAnimationTask::ApplyAnimationData()
       SetCurrentFrameNumber(animationData.currentFrame);
     }
 
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_NOTIFY_AFTER_RASTERIZATION)
+    {
+      mNotifyAfterRasterization = animationData.notifyAfterRasterization;
+    }
+
     if(animationData.resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
     {
       mVectorRenderer.InvalidateBuffer();
index 46976a5..c741be1 100644 (file)
@@ -67,15 +67,16 @@ public:
    */
   enum ResendFlags
   {
-    RESEND_PLAY_RANGE          = 1 << 0,
-    RESEND_LOOP_COUNT          = 1 << 1,
-    RESEND_STOP_BEHAVIOR       = 1 << 2,
-    RESEND_LOOPING_MODE        = 1 << 3,
-    RESEND_CURRENT_FRAME       = 1 << 4,
-    RESEND_SIZE                = 1 << 5,
-    RESEND_PLAY_STATE          = 1 << 6,
-    RESEND_NEED_RESOURCE_READY = 1 << 7,
-    RESEND_DYNAMIC_PROPERTY    = 1 << 8
+    RESEND_PLAY_RANGE                 = 1 << 0,
+    RESEND_LOOP_COUNT                 = 1 << 1,
+    RESEND_STOP_BEHAVIOR              = 1 << 2,
+    RESEND_LOOPING_MODE               = 1 << 3,
+    RESEND_CURRENT_FRAME              = 1 << 4,
+    RESEND_SIZE                       = 1 << 5,
+    RESEND_PLAY_STATE                 = 1 << 6,
+    RESEND_NEED_RESOURCE_READY        = 1 << 7,
+    RESEND_DYNAMIC_PROPERTY           = 1 << 8,
+    RESEND_NOTIFY_AFTER_RASTERIZATION = 1 << 9,
   };
 
   /**
@@ -94,22 +95,24 @@ public:
       width(0),
       height(0),
       loopCount(-1),
-      playStateId(0)
+      playStateId(0),
+      notifyAfterRasterization(false)
     {
     }
 
     AnimationData& operator=(const AnimationData& rhs)
     {
       resendFlag |= rhs.resendFlag; // OR resend flag
-      playRange    = rhs.playRange;
-      playState    = rhs.playState;
-      stopBehavior = rhs.stopBehavior;
-      loopingMode  = rhs.loopingMode;
-      currentFrame = rhs.currentFrame;
-      width        = rhs.width;
-      height       = rhs.height;
-      loopCount    = rhs.loopCount;
-      playStateId  = rhs.playStateId;
+      playRange                = rhs.playRange;
+      playState                = rhs.playState;
+      stopBehavior             = rhs.stopBehavior;
+      loopingMode              = rhs.loopingMode;
+      currentFrame             = rhs.currentFrame;
+      width                    = rhs.width;
+      height                   = rhs.height;
+      loopCount                = rhs.loopCount;
+      playStateId              = rhs.playStateId;
+      notifyAfterRasterization = rhs.notifyAfterRasterization;
       dynamicProperties.insert(dynamicProperties.end(), rhs.dynamicProperties.begin(), rhs.dynamicProperties.end());
       return *this;
     }
@@ -125,6 +128,7 @@ public:
     uint32_t                             height;
     int32_t                              loopCount;
     uint32_t                             playStateId;
+    bool                                 notifyAfterRasterization;
   };
 
   /**
@@ -179,12 +183,6 @@ public:
   void SetAnimationFinishedCallback(CallbackBase* callback);
 
   /**
-   * @brief This callback is called when we want to force render next frame.
-   * @param[in] callback The force render once callback
-   */
-  void SetForceRenderOnceCallback(CallbackBase* callback);
-
-  /**
    * @brief Gets the playing range in frame number.
    * @param[out] startFrame The frame number to specify minimum progress.
    * @param[out] endFrame The frame number to specify maximum progress.
@@ -263,6 +261,16 @@ public:
    */
   bool IsAnimating();
 
+  void KeepRasterizedBuffer(bool enableFrameCache)
+  {
+    mEnableFrameCache = enableFrameCache;
+  }
+
+  bool IsKeptRasterizedBuffer() const
+  {
+    return mEnableFrameCache;
+  }
+
 public: // Implementation of AsyncTask
   /**
    * @copydoc Dali::AsyncTask::Process()
@@ -282,16 +290,6 @@ public: // Implementation of AsyncTask
     return "VectorAnimationTask";
   }
 
-  void KeepRasterizedBuffer(bool enableFrameCache)
-  {
-    mEnableFrameCache = enableFrameCache;
-  }
-
-  bool IsKeptRasterizedBuffer()
-  {
-    return mEnableFrameCache;
-  }
-
 private:
   /**
    * @brief Loads the animation file.
@@ -399,7 +397,6 @@ private:
   Mutex                                mMutex;
   ResourceReadySignalType              mResourceReadySignal;
   std::unique_ptr<CallbackBase>        mAnimationFinishedCallback{};
-  std::unique_ptr<CallbackBase>        mForceRenderOnceCallback{};
   std::unique_ptr<CallbackBase>        mLoadCompletedCallback{};
   mutable Property::Map                mCachedLayerInfo;
   mutable Property::Map                mCachedMarkerInfo;
@@ -433,6 +430,7 @@ private:
   mutable bool                         mLayerInfoCached : 1;
   mutable bool                         mMarkerInfoCached : 1;
   bool                                 mEnableFrameCache : 1;
+  bool                                 mNotifyAfterRasterization : 1;
   bool                                 mSizeUpdated : 1;
 };
 
index b07ba5b..5638ec3 100644 (file)
@@ -46,10 +46,12 @@ VectorAnimationThread::VectorAnimationThread()
   mSleepThread(MakeCallback(this, &VectorAnimationThread::OnAwakeFromSleep)),
   mConditionalWait(),
   mEventTriggerMutex(),
+  mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
   mNeedToSleep(false),
   mDestroyThread(false),
-  mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
-  mTraceFactory(Dali::Adaptor::Get().GetTraceFactory())
+  mEventTriggered(false),
+  mForceRenderOnce(false)
 {
   mAsyncTaskManager = Dali::AsyncTaskManager::Get();
   mSleepThread.Start();
@@ -184,6 +186,21 @@ void VectorAnimationThread::RemoveEventTriggerCallbacks(CallbackBase* callback)
   }
 }
 
+void VectorAnimationThread::RequestForceRenderOnce()
+{
+  Mutex::ScopedLock lock(mEventTriggerMutex);
+  if(!mDestroyThread)
+  {
+    mForceRenderOnce = true;
+
+    if(!mEventTriggered)
+    {
+      mEventTrigger->Trigger();
+      mEventTriggered = true;
+    }
+  }
+}
+
 void VectorAnimationThread::Run()
 {
   SetThreadName("VectorAnimationThread");
@@ -285,6 +302,18 @@ void VectorAnimationThread::OnEventCallbackTriggered()
     }
     CallbackBase::Execute(*callbackPair.first, callbackPair.second);
   }
+  // Request update once if we need.
+  {
+    Mutex::ScopedLock lock(mEventTriggerMutex);
+    if(!mDestroyThread && mForceRenderOnce)
+    {
+      mForceRenderOnce = false;
+      if(Dali::Adaptor::IsAvailable())
+      {
+        Dali::Adaptor::Get().UpdateOnce();
+      }
+    }
+  }
 }
 
 std::pair<CallbackBase*, uint32_t> VectorAnimationThread::GetNextEventCallback()
index b1f608a..8b820cc 100644 (file)
@@ -90,6 +90,11 @@ public:
    */
   void RemoveEventTriggerCallbacks(CallbackBase* callback);
 
+  /**
+   * @brief Request to event callback from rasterize thread. This is called when we want to ensure rendering next frame.
+   */
+  void RequestForceRenderOnce();
+
 protected:
   /**
    * @brief The entry function of the animation thread.
@@ -149,8 +154,9 @@ private:
     std::chrono::time_point<std::chrono::steady_clock> mSleepTimePoint;
     const Dali::LogFactoryInterface&                   mLogFactory;
     const Dali::TraceFactoryInterface&                 mTraceFactory;
-    bool                                               mNeedToSleep;
-    bool                                               mDestroyThread;
+
+    bool mNeedToSleep : 1;
+    bool mDestroyThread : 1;
   };
 
 private:
@@ -169,12 +175,14 @@ private:
   ConditionalWait                                 mConditionalWait;
   Mutex                                           mEventTriggerMutex;
   std::unique_ptr<EventThreadCallback>            mEventTrigger{};
-  bool                                            mNeedToSleep;
-  bool                                            mDestroyThread;
-  bool                                            mEventTriggered{false};
   const Dali::LogFactoryInterface&                mLogFactory;
   const Dali::TraceFactoryInterface&              mTraceFactory;
   Dali::AsyncTaskManager                          mAsyncTaskManager;
+
+  bool mNeedToSleep : 1;
+  bool mDestroyThread : 1;
+  bool mEventTriggered : 1;
+  bool mForceRenderOnce : 1;
 };
 
 } // namespace Internal
index 6d89342..ae39540 100644 (file)
@@ -212,6 +212,7 @@ const char* const MASK_TEXTURE_RATIO_NAME("maskTextureRatio");
 const char* const FAST_TRACK_UPLOADING_NAME("fastTrackUploading");
 const char* const ENABLE_BROKEN_IMAGE("enableBrokenImage");
 const char* const ENABLE_FRAME_CACHE("enableFrameCache");
+const char* const NOTIFY_AFTER_RASTERIZATION("notifyAfterRasterization");
 
 // Text visual
 const char* const TEXT_PROPERTY("text");
index cc97413..9835299 100644 (file)
@@ -114,6 +114,7 @@ extern const char* const MASK_TEXTURE_RATIO_NAME;
 extern const char* const FAST_TRACK_UPLOADING_NAME;
 extern const char* const ENABLE_BROKEN_IMAGE;
 extern const char* const ENABLE_FRAME_CACHE;
+extern const char* const NOTIFY_AFTER_RASTERIZATION;
 
 // Text visual
 extern const char* const TEXT_PROPERTY;