[Tizen] Support asan build option accepted/tizen_unified accepted/tizen_unified_x tizen accepted/tizen/unified/20240520.131908 accepted/tizen/unified/x/20240521.022225
authorEunki, Hong <eunkiki.hong@samsung.com>
Mon, 20 May 2024 05:17:51 +0000 (14:17 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 20 May 2024 05:17:56 +0000 (14:17 +0900)
This reverts commit 68e257653cf392015f3efb6331faa8e682255ce8.

Change-Id: I8e30c55ad463cd0b8098feccce5b04b0154ec0f9

128 files changed:
automated-tests/src/dali-shader-generator/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Accessible.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Value.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h
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/dali-toolkit-test-utils/toolkit-clipboard.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.h
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.h
dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert
dali-scene3d/public-api/loader/buffer-definition.cpp
dali-scene3d/public-api/loader/material-definition.cpp
dali-toolkit/devel-api/controls/control-accessible.cpp
dali-toolkit/devel-api/controls/control-depth-index-ranges.h
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
dali-toolkit/devel-api/controls/text-controls/text-field-devel.cpp
dali-toolkit/devel-api/controls/text-controls/text-field-devel.h
dali-toolkit/devel-api/controls/text-controls/text-label-devel.h
dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h
dali-toolkit/devel-api/text/range.h
dali-toolkit/devel-api/text/spans/base-span.h
dali-toolkit/devel-api/visual-factory/visual-base.h
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
dali-toolkit/internal/builder/tree-node-manipulator.cpp
dali-toolkit/internal/builder/tree-node-manipulator.h
dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp
dali-toolkit/internal/controls/buttons/push-button-impl.cpp
dali-toolkit/internal/controls/buttons/radio-button-impl.cpp
dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/gl-view/drawable-view-impl.cpp
dali-toolkit/internal/controls/gl-view/drawable-view-impl.h
dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp
dali-toolkit/internal/controls/gl-view/gl-view-impl.h
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.h
dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
dali-toolkit/internal/controls/slider/slider-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-editor-property-handler.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/web-view/web-view-impl.cpp
dali-toolkit/internal/graphics/shaders/text-atlas-shader.vert
dali-toolkit/internal/text/controller/text-controller-event-handler.cpp
dali-toolkit/internal/text/controller/text-controller-impl.cpp
dali-toolkit/internal/text/controller/text-controller-impl.h
dali-toolkit/internal/text/controller/text-controller-text-updater.cpp
dali-toolkit/internal/text/controller/text-controller-text-updater.h
dali-toolkit/internal/text/controller/text-controller.cpp
dali-toolkit/internal/text/controller/text-controller.h
dali-toolkit/internal/text/glyph-run.h
dali-toolkit/internal/text/line-run.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/text-typesetter.h
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/spannable/span-ranges-container-impl.h
dali-toolkit/internal/text/spannable/spannable-impl.h
dali-toolkit/internal/text/spannable/spannable-string-impl.h
dali-toolkit/internal/text/spannable/spanned-impl.h
dali-toolkit/internal/text/spannable/spans/base-span-impl.h
dali-toolkit/internal/text/string-text/character-sequence-impl.h
dali-toolkit/internal/text/string-text/range-impl.h
dali-toolkit/internal/text/text-effects-style.cpp
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-scroller.cpp
dali-toolkit/internal/text/text-scroller.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp
dali-toolkit/internal/texture-manager/texture-manager-impl.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/image-cache.cpp
dali-toolkit/internal/visuals/animated-image/image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
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-manager.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.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/gradient/gradient-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.h
dali-toolkit/internal/visuals/transition-data-impl.cpp
dali-toolkit/internal/visuals/transition-data-impl.h
dali-toolkit/internal/visuals/visual-base-data-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/image-view/image-view.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/shader-generator/shader-generator.cpp
packaging/dali-toolkit.spec

index 30502d8..e3b52cd 100644 (file)
@@ -110,25 +110,37 @@ ADD_CUSTOM_TARGET(test_invalid_indir ALL COMMAND ${SHADER_GENERATOR} ONE TWO > /
 ADD_CUSTOM_TARGET(
   test_check_built_in_created
   ALL
-  COMMAND ${SHADER_GENERATOR} . ${GENERATED_FOLDER} | grep builtin-shader | wc -l | grep 2 > /dev/null 2>&1 && echo "test_check_built_in_created Succeeded"
+  COMMAND rm -rf ${GENERATED_FOLDER}/check_built_in
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/check_built_in/generated | grep builtin-shader | wc -l | grep 2 > /dev/null 2>&1 && echo "test_check_built_in_created Succeeded"
   VERBATIM)
 ADD_CUSTOM_TARGET(
   test_check_built_in_not_created
   ALL
-  COMMAND ${SHADER_GENERATOR} --skip . ${GENERATED_FOLDER} | grep builtin-shader > /dev/null 2>&1 || echo "test_check_built_in_not_created Succeeded"
+  COMMAND rm -rf ${GENERATED_FOLDER}/skip_built_in
+  COMMAND ${SHADER_GENERATOR} --skip ${SHADER_FOLDER} ${GENERATED_FOLDER}/skip_built_in/generated | grep builtin-shader > /dev/null 2>&1 && exit 1 || echo "test_check_built_in_not_created Succeeded"
   VERBATIM)
 ADD_CUSTOM_TARGET(
   test_frag_correct
   ALL
-  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_FRAGMENT_SHADER_FRAG" | grep "fragment-shader-frag.h" > /dev/null 2>&1 && echo "test_frag_correct Succeeded"
+  COMMAND rm -rf ${GENERATED_FOLDER}/frag_correct
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/frag_correct/generated | grep "SHADER_FRAGMENT_SHADER_FRAG" | grep "fragment-shader-frag.h" > /dev/null 2>&1 && echo "test_frag_correct Succeeded"
   VERBATIM)
 ADD_CUSTOM_TARGET(
   test_vert_correct
   ALL
-  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_VERTEX_SHADER_VERT" | grep "vertex-shader-vert.h" > /dev/null 2>&1 && echo "test_vert_correct Succeeded"
+  COMMAND rm -rf ${GENERATED_FOLDER}/vert_correct
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/vert_correct/generated | grep "SHADER_VERTEX_SHADER_VERT" | grep "vertex-shader-vert.h" > /dev/null 2>&1 && echo "test_vert_correct Succeeded"
   VERBATIM)
 ADD_CUSTOM_TARGET(
   test_def_correct
   ALL
-  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && echo "test_def_correct Succeeded"
+  COMMAND rm -rf ${GENERATED_FOLDER}/def_correct
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/def_correct/generated | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && echo "test_def_correct Succeeded"
+  VERBATIM)
+ADD_CUSTOM_TARGET(
+  test_no_overwrite
+  ALL
+  COMMAND rm -rf ${GENERATED_FOLDER}/no_overwrite
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/no_overwrite/generated | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1
+  COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER}/no_overwrite/generated | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && exit 1 || echo "test_no_overwrite Succeeded"
   VERBATIM)
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 ff95317..d19755a 100644 (file)
 #include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
 #include <dali/devel-api/atspi-interfaces/accessible.h>
+#include <dali/devel-api/atspi-interfaces/component.h>
 #include <dali/devel-api/atspi-interfaces/value.h>
 
 #include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
 
+#include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.h>
 #include <automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h>
 
 using namespace Dali::Accessibility;
@@ -87,17 +89,20 @@ int utcDaliAccessibilityProgressBarGetMinimumIncrement(void)
 int utcDaliAccessibilityProgressBarGetSetCurrent(void)
 {
   ToolkitTestApplication application;
+  Dali::Accessibility::TestEnableSC(true);
 
   Toolkit::ProgressBar progress_bar = Toolkit::ProgressBar::New();
   auto q = Dali::Accessibility::Accessible::Get(progress_bar);
   auto x = dynamic_cast< Dali::Accessibility::Value* >( q );
   DALI_TEST_CHECK( x );
+  DALI_TEST_CHECK(Dali::Accessibility::Component::DownCast(q)->GrabHighlight());
   DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
   DALI_TEST_EQUALS( x->SetCurrent( 2.0 ), false, TEST_LOCATION );
   DALI_TEST_EQUALS( x->SetCurrent( 0.25 ), true, TEST_LOCATION );
   DALI_TEST_EQUALS( x->GetCurrent(), 0.25, TEST_LOCATION );
   DALI_TEST_EQUALS( x->GetValueText().empty(), true, TEST_LOCATION ); // not implemented
 
+  Dali::Accessibility::TestEnableSC(false);
   END_TEST;
 }
 
@@ -169,6 +174,7 @@ int utcDaliAccessibilityScrollBarGetMinimumIncrement(void)
 int utcDaliAccessibilityScrollBarGetSetCurrent(void)
 {
   ToolkitTestApplication application;
+  Dali::Accessibility::TestEnableSC(true);
 
   // Create a source actor that owns the scroll properties required by the scroll bar
   Actor sourceActor = Actor::New();
@@ -189,12 +195,14 @@ int utcDaliAccessibilityScrollBarGetSetCurrent(void)
   auto q = Dali::Accessibility::Accessible::Get(scroll_bar);
   auto x = dynamic_cast< Dali::Accessibility::Value* >( q );
   DALI_TEST_CHECK( x );
+  DALI_TEST_CHECK(Dali::Accessibility::Component::DownCast(q)->GrabHighlight());
   DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
   DALI_TEST_EQUALS( x->SetCurrent( 1000.0 ), false, TEST_LOCATION );
   DALI_TEST_EQUALS( x->SetCurrent( 50.0 ), false, TEST_LOCATION );
   DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
   DALI_TEST_EQUALS( x->GetValueText().empty(), true, TEST_LOCATION ); // not implemented
 
+  Dali::Accessibility::TestEnableSC(false);
   END_TEST;
 }
 
@@ -240,11 +248,13 @@ int utcDaliAccessibilitySliderGetMinimumIncrement(void)
 int utcDaliAccessibilitySliderGetSetCurrent(void)
 {
   ToolkitTestApplication application;
+  Dali::Accessibility::TestEnableSC(true);
 
   Toolkit::Slider slider = Toolkit::Slider::New();
   auto q = Dali::Accessibility::Accessible::Get(slider);
   auto x = dynamic_cast< Dali::Accessibility::Value* >( q );
   DALI_TEST_CHECK( x );
+  DALI_TEST_CHECK(Dali::Accessibility::Component::DownCast(q)->GrabHighlight());
   DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION );
   DALI_TEST_EQUALS( x->SetCurrent( 2.0 ), false, TEST_LOCATION );
   DALI_TEST_EQUALS( x->SetCurrent( 0.25 ), true, TEST_LOCATION );
@@ -269,5 +279,7 @@ int utcDaliAccessibilitySliderGetSetCurrent(void)
   // depending if the new value is greater/less than current value
   DALI_TEST_CHECK( x->SetCurrent( 0.2f ) );
   DALI_TEST_EQUALS( static_cast<float>( x->GetCurrent() ),  marks[2].Get<float>(), TEST_LOCATION );
+
+  Dali::Accessibility::TestEnableSC(false);
   END_TEST;
 }
index 6a3a84a..774cce1 100644 (file)
@@ -1362,3 +1362,44 @@ int UtcDaliTextControllerDeleteSurroundings(void)
 
   END_TEST;
 }
+
+int UtcDaliTextControllerMultipleInsert(void)
+{
+  tet_infoline(" UtcDaliTextControllerMultipleInsert");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextField(controller);
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation(*controller.Get());
+
+  DALI_TEST_EQUALS(EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION);
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+
+  // When maid thread is busy, multiple event might be executed.
+  InputMethodContext::EventData imfEvent1 = InputMethodContext::EventData(InputMethodContext::PRE_EDIT, "A", 0, 1);
+  InputMethodContext::EventData imfEvent2 = InputMethodContext::EventData(InputMethodContext::PRE_EDIT, "AAAAA", 0, 5);
+  controller->OnInputMethodContextEvent(inputMethodContext, imfEvent1);
+  controller->OnInputMethodContextEvent(inputMethodContext, imfEvent2);
+
+  // Perform a relayout
+  const Size size(application.GetScene().GetSize());
+
+  application.SendNotification();
+  application.Render();
+
+  controller->Relayout(size);
+
+  std::string text;
+  controller->GetText(text);
+
+  DALI_TEST_EQUALS("AAAAA", text, TEST_LOCATION);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
index 56b3b5e..262afcf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 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.
 #include "dummy-control.h"
 
 #include <dali-toolkit/dali-toolkit.h>
-#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 
 namespace Dali
 {
-
 namespace Toolkit
 {
-
 DummyControl::DummyControl()
 {
 }
 
 DummyControl::DummyControl(const DummyControl& control)
-: Control( control )
+: Control(control)
 {
 }
 
@@ -40,60 +38,60 @@ DummyControl::~DummyControl()
 {
 }
 
-DummyControl DummyControl::DownCast( BaseHandle handle )
+DummyControl DummyControl::DownCast(BaseHandle handle)
 {
   return Control::DownCast<DummyControl, DummyControlImpl>(handle);
 }
 
 DummyControl& DummyControl::operator=(const DummyControl& control)
 {
-  Control::operator=( control );
+  Control::operator=(control);
   return *this;
 }
 
 // Used to test signal connections
-void DummyControlImpl::CustomSlot1( Actor actor )
+void DummyControlImpl::CustomSlot1(Actor actor)
 {
   mCustomSlot1Called = true;
 }
 
-namespace {
-
+namespace
+{
 BaseHandle Create()
 {
   return DummyControlImpl::New();
 }
 
-DALI_TYPE_REGISTRATION_BEGIN( Toolkit::DummyControl, Toolkit::Control, Create );
+DALI_TYPE_REGISTRATION_BEGIN(Toolkit::DummyControl, Toolkit::Control, Create);
 DALI_TYPE_REGISTRATION_END()
 
 Dali::PropertyRegistration dummyControlVisualProperty01(
-  typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+  typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
 
 Dali::PropertyRegistration dummyControlVisualProperty02(
-  typeRegistration, "testVisual2", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+  typeRegistration, "testVisual2", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
 
 Dali::PropertyRegistration dummyControlVisualProperty03(
-  typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+  typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
 
 Dali::PropertyRegistration dummyControlVisualProperty04(
-  typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+  typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
 
 Dali::PropertyRegistration dummyControlVisualProperty05(
-  typeRegistration, "labelVisual", Dali::Toolkit::DummyControl::Property::LABEL_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+  typeRegistration, "labelVisual", Dali::Toolkit::DummyControl::Property::LABEL_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty);
 
-}
+} // namespace
 
 DummyControl DummyControlImpl::New()
 {
-  IntrusivePtr< DummyControlImpl > impl = new DummyControlImpl;
-  DummyControl control( *impl );
+  IntrusivePtr<DummyControlImpl> impl = new DummyControlImpl;
+  DummyControl                   control(*impl);
   impl->Initialize();
   return control;
 }
 
 DummyControlImpl::DummyControlImpl()
-: Control( ControlBehaviour() ),
+: Control(ControlBehaviour()),
   mCustomSlot1Called(false)
 {
 }
@@ -102,69 +100,80 @@ DummyControlImpl::~DummyControlImpl()
 {
 }
 
-void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::Base visual )
+void DummyControlImpl::RegisterVisual(Property::Index index, Toolkit::Visual::Base visual)
+{
+  DevelControl::RegisterVisual(*this, index, visual);
+
+  VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+  if(iter == mRegisteredVisualIndices.end())
+  {
+    mRegisteredVisualIndices.push_back(index);
+  }
+}
+
+void DummyControlImpl::RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, bool enabled)
 {
-  DevelControl::RegisterVisual( *this, index, visual );
+  DevelControl::RegisterVisual(*this, index, visual, enabled);
 
-  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
-  if( iter == mRegisteredVisualIndices.end() )
+  VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+  if(iter == mRegisteredVisualIndices.end())
   {
     mRegisteredVisualIndices.push_back(index);
   }
 }
 
-void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled )
+void DummyControlImpl::RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, int depthIndex)
 {
-  DevelControl::RegisterVisual( *this, index, visual, enabled );
+  DevelControl::RegisterVisual(*this, index, visual, depthIndex);
 
-  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
-  if( iter == mRegisteredVisualIndices.end() )
+  VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+  if(iter == mRegisteredVisualIndices.end())
   {
     mRegisteredVisualIndices.push_back(index);
   }
 }
 
-void DummyControlImpl::UnregisterVisual( Property::Index index )
+void DummyControlImpl::UnregisterVisual(Property::Index index)
 {
-  DevelControl::UnregisterVisual( *this, index );
+  DevelControl::UnregisterVisual(*this, index);
 
-  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
-  if( iter != mRegisteredVisualIndices.end() )
+  VisualIndices::iterator iter = std::find(mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index);
+  if(iter != mRegisteredVisualIndices.end())
   {
     mRegisteredVisualIndices.erase(iter);
   }
 }
 
-Toolkit::Visual::Base DummyControlImpl::GetVisual( Property::Index index )
+Toolkit::Visual::Base DummyControlImpl::GetVisual(Property::Index index)
 {
-  return DevelControl::GetVisual( *this, index );
+  return DevelControl::GetVisual(*this, index);
 }
 
-void DummyControlImpl::EnableVisual( Property::Index index, bool enabled )
+void DummyControlImpl::EnableVisual(Property::Index index, bool enabled)
 {
-  DevelControl::EnableVisual( *this, index, enabled );
+  DevelControl::EnableVisual(*this, index, enabled);
 }
 
-bool DummyControlImpl::IsVisualEnabled( Property::Index index )
+bool DummyControlImpl::IsVisualEnabled(Property::Index index)
 {
-  return DevelControl::IsVisualEnabled( *this, index );
+  return DevelControl::IsVisualEnabled(*this, index);
 }
 
-Animation DummyControlImpl::CreateTransition( const Toolkit::TransitionData& transition )
+Animation DummyControlImpl::CreateTransition(const Toolkit::TransitionData& transition)
 {
-  return DevelControl::CreateTransition( *this, transition );
+  return DevelControl::CreateTransition(*this, transition);
 }
 
-void DummyControlImpl::DoAction( Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes )
+void DummyControlImpl::DoAction(Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes)
 {
-  DummyControl control( *this );
-  DevelControl::DoAction(  control, index, action, attributes);
+  DummyControl control(*this);
+  DevelControl::DoAction(control, index, action, attributes);
 }
 
-void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value )
+void DummyControlImpl::SetProperty(BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value)
 {
-  Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
-  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
+  Toolkit::DummyControl control   = Toolkit::DummyControl::DownCast(Dali::BaseHandle(object));
+  DummyControlImpl&     dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
 
   switch(index)
   {
@@ -175,10 +184,10 @@ void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index in
     case Toolkit::DummyControl::Property::LABEL_VISUAL:
     {
       const Property::Map* map = value.GetMap();
-      if( map != NULL )
+      if(map != NULL)
       {
         VisualFactory visualFactory = VisualFactory::Get();
-        Visual::Base visual = visualFactory.CreateVisual(*map);
+        Visual::Base  visual        = visualFactory.CreateVisual(*map);
         dummyImpl.RegisterVisual(index, visual);
       }
       break;
@@ -186,27 +195,26 @@ void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index in
   }
 }
 
-Property::Value DummyControlImpl::GetProperty( BaseObject* object, Dali::Property::Index propertyIndex )
+Property::Value DummyControlImpl::GetProperty(BaseObject* object, Dali::Property::Index propertyIndex)
 {
-  Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
-  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>( control.GetImplementation() );
+  Toolkit::DummyControl control   = Toolkit::DummyControl::DownCast(Dali::BaseHandle(object));
+  DummyControlImpl&     dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
 
-  Visual::Base visual = dummyImpl.GetVisual( propertyIndex );
+  Visual::Base  visual = dummyImpl.GetVisual(propertyIndex);
   Property::Map map;
-  if( visual )
+  if(visual)
   {
-    visual.CreatePropertyMap( map );
+    visual.CreatePropertyMap(map);
   }
   Dali::Property::Value value = map;
 
   return value;
 }
 
-
 Toolkit::DummyControl Impl::DummyControl::New()
 {
-  IntrusivePtr< Toolkit::Impl::DummyControl > impl = new Toolkit::Impl::DummyControl;
-  Toolkit::DummyControl control( *impl );
+  IntrusivePtr<Toolkit::Impl::DummyControl> impl = new Toolkit::Impl::DummyControl;
+  Toolkit::DummyControl                     control(*impl);
   impl->Initialize();
   return control;
 }
@@ -245,29 +253,75 @@ Impl::DummyControl::~DummyControl()
   ++destructorCount;
 }
 
-void Impl::DummyControl::OnInitialize() { initializeCalled = true; }
-bool Impl::DummyControl::OnAccessibilityActivated() { activatedCalled = true; return true; }
-bool Impl::DummyControl::OnAccessibilityValueChange( bool isIncrease )
+void Impl::DummyControl::OnInitialize()
+{
+  initializeCalled = true;
+}
+bool Impl::DummyControl::OnAccessibilityActivated()
 {
-  onAccValueChangeCalled = true; return true;
+  activatedCalled = true;
+  return true;
+}
+bool Impl::DummyControl::OnAccessibilityValueChange(bool isIncrease)
+{
+  onAccValueChangeCalled = true;
+  return true;
 }
 
-void Impl::DummyControl::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+void Impl::DummyControl::OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change)
 {
   themeChangeCalled = change == StyleChange::THEME_CHANGE;
-  fontChangeCalled = change == StyleChange::DEFAULT_FONT_SIZE_CHANGE;
-}
-void Impl::DummyControl::OnPinch(const PinchGesture& pinch) { pinchCalled = true; }
-void Impl::DummyControl::OnPan(const PanGesture& pan) { panCalled = true; }
-void Impl::DummyControl::OnTap(const TapGesture& tap) { tapCalled = true; }
-void Impl::DummyControl::OnLongPress(const LongPressGesture& longPress) { longPressCalled = true; }
-void Impl::DummyControl::OnSceneConnection( int depth ) { Control::OnSceneConnection( depth ); stageConnectionCalled = true; }
-void Impl::DummyControl::OnSceneDisconnection() { stageDisconnectionCalled = true; Control::OnSceneDisconnection(); }
-void Impl::DummyControl::OnChildAdd(Actor& child) { childAddCalled = true; }
-void Impl::DummyControl::OnChildRemove(Actor& child) { childRemoveCalled = true; }
-void Impl::DummyControl::OnSizeSet(const Vector3& targetSize) { Control::OnSizeSet( targetSize ); sizeSetCalled = true; }
-void Impl::DummyControl::OnSizeAnimation(Animation& animation, const Vector3& targetSize) { Control::OnSizeAnimation( animation, targetSize ); sizeAnimationCalled = true; }
-bool Impl::DummyControl::OnKeyEvent(const KeyEvent& event) { keyEventCalled = true; return false;}
+  fontChangeCalled  = change == StyleChange::DEFAULT_FONT_SIZE_CHANGE;
+}
+void Impl::DummyControl::OnPinch(const PinchGesture& pinch)
+{
+  pinchCalled = true;
+}
+void Impl::DummyControl::OnPan(const PanGesture& pan)
+{
+  panCalled = true;
+}
+void Impl::DummyControl::OnTap(const TapGesture& tap)
+{
+  tapCalled = true;
+}
+void Impl::DummyControl::OnLongPress(const LongPressGesture& longPress)
+{
+  longPressCalled = true;
+}
+void Impl::DummyControl::OnSceneConnection(int depth)
+{
+  Control::OnSceneConnection(depth);
+  stageConnectionCalled = true;
+}
+void Impl::DummyControl::OnSceneDisconnection()
+{
+  stageDisconnectionCalled = true;
+  Control::OnSceneDisconnection();
+}
+void Impl::DummyControl::OnChildAdd(Actor& child)
+{
+  childAddCalled = true;
+}
+void Impl::DummyControl::OnChildRemove(Actor& child)
+{
+  childRemoveCalled = true;
+}
+void Impl::DummyControl::OnSizeSet(const Vector3& targetSize)
+{
+  Control::OnSizeSet(targetSize);
+  sizeSetCalled = true;
+}
+void Impl::DummyControl::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
+{
+  Control::OnSizeAnimation(animation, targetSize);
+  sizeAnimationCalled = true;
+}
+bool Impl::DummyControl::OnKeyEvent(const KeyEvent& event)
+{
+  keyEventCalled = true;
+  return false;
+}
 void Impl::DummyControl::OnKeyInputFocusGained()
 {
   if(this->HasKeyInputFocus())
@@ -283,41 +337,41 @@ void Impl::DummyControl::OnKeyInputFocusLost()
   }
 }
 
-void Impl::DummyControl::SetLayout( Property::Index visualIndex, Property::Map& map )
+void Impl::DummyControl::SetLayout(Property::Index visualIndex, Property::Map& map)
 {
-  Property::Value value( map );
+  Property::Value value(map);
   mLayouts[visualIndex] = value;
 }
 
-void Impl::DummyControl::OnRelayout( const Vector2& size, RelayoutContainer& container )
+void Impl::DummyControl::OnRelayout(const Vector2& size, RelayoutContainer& container)
 {
-  if ( mRelayoutCallback )
+  if(mRelayoutCallback)
   {
-    mRelayoutCallback( size );  // Execute callback if set
+    mRelayoutCallback(size); // Execute callback if set
   }
 
   Property::Map emptyMap;
 
-  for( VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end() ; ++iter )
+  for(VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end(); ++iter)
   {
-    Visual::Base visual = GetVisual(*iter);
-    Property::Value value = mLayouts[*iter];
-    Property::Map* map = NULL;
+    Visual::Base    visual = GetVisual(*iter);
+    Property::Value value  = mLayouts[*iter];
+    Property::Map*  map    = NULL;
 
-    if( value.GetType() != Property::NONE )
+    if(value.GetType() != Property::NONE)
     {
       map = value.GetMap();
     }
-    if( map == NULL )
+    if(map == NULL)
     {
       map = &emptyMap;
     }
 
-    visual.SetTransformAndSize( *map, size );
+    visual.SetTransformAndSize(*map, size);
   }
 }
 
-void Impl::DummyControl::SetRelayoutCallback( RelayoutCallbackFunc callback  )
+void Impl::DummyControl::SetRelayoutCallback(RelayoutCallbackFunc callback)
 {
   mRelayoutCallback = callback;
 }
@@ -326,25 +380,23 @@ Vector3 Impl::DummyControl::GetNaturalSize()
 {
   Vector2 currentSize;
 
-  for( auto elem : mRegisteredVisualIndices )
+  for(auto elem : mRegisteredVisualIndices)
   {
-    Vector2 naturalSize;
+    Vector2      naturalSize;
     Visual::Base visual = GetVisual(elem);
-    visual.GetNaturalSize( naturalSize );
-    currentSize.width = std::max( naturalSize.width, currentSize.width );
-    currentSize.height = std::max( naturalSize.height, currentSize.height );
+    visual.GetNaturalSize(naturalSize);
+    currentSize.width  = std::max(naturalSize.width, currentSize.width);
+    currentSize.height = std::max(naturalSize.height, currentSize.height);
   }
 
-  return Vector3( currentSize );
+  return Vector3(currentSize);
 }
 
-
-
-DummyControl DummyControl::New( bool override )
+DummyControl DummyControl::New(bool override)
 {
   DummyControl control;
 
-  if (override)
+  if(override)
   {
     control = Impl::DummyControl::New();
   }
@@ -356,13 +408,13 @@ DummyControl DummyControl::New( bool override )
   return control;
 }
 
-DummyControl::DummyControl( DummyControlImpl& implementation )
-: Control( implementation )
+DummyControl::DummyControl(DummyControlImpl& implementation)
+: Control(implementation)
 {
 }
 
-DummyControl::DummyControl( Dali::Internal::CustomActor* internal )
-: Control( internal )
+DummyControl::DummyControl(Dali::Internal::CustomActor* internal)
+: Control(internal)
 {
   VerifyCustomActorPointer<DummyControlImpl>(internal);
 }
index 6f79c36..2908ad1 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEST_DUMMY_CONTROL_H
 
 /*
- * Copyright (c) 2020 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.
 
 namespace Dali
 {
-
 namespace Toolkit
 {
-
 class DummyControlImpl;
 class TransitionData;
 
@@ -47,7 +45,7 @@ public:
   enum PropertyRange
   {
     PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
-    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property index
+    PROPERTY_END_INDEX   = PROPERTY_START_INDEX + 1000              ///< Reserve property index
   };
 
   struct Property
@@ -66,17 +64,15 @@ public:
   DummyControl(const DummyControl& control);
   ~DummyControl();
 
-  static DummyControl New( bool override = false );
-
-  static DummyControl DownCast( BaseHandle handle );
+  static DummyControl New(bool override = false);
 
+  static DummyControl DownCast(BaseHandle handle);
 
   DummyControl& operator=(const DummyControl& control);
 
 public: // Not intended for application developers
-
-  DummyControl( DummyControlImpl& implementation );
-  DummyControl( Dali::Internal::CustomActor* internal );
+  DummyControl(DummyControlImpl& implementation);
+  DummyControl(Dali::Internal::CustomActor* internal);
 };
 
 /**
@@ -86,40 +82,57 @@ public: // Not intended for application developers
 class DummyControlImpl : public Toolkit::Internal::Control
 {
 public:
-
   static DummyControl New();
 
 public:
-  inline void EnableGestureDetection(GestureType::Value type) { Internal::Control::EnableGestureDetection(type); }
-  inline void DisableGestureDetection(GestureType::Value type) { Internal::Control::DisableGestureDetection(type); }
-  inline PinchGestureDetector GetPinchGestureDetector() const { return Internal::Control::GetPinchGestureDetector(); }
-  inline PanGestureDetector GetPanGestureDetector() const { return Internal::Control::GetPanGestureDetector(); }
-  inline TapGestureDetector GetTapGestureDetector() const { return Internal::Control::GetTapGestureDetector(); }
-  inline LongPressGestureDetector GetLongPressGestureDetector() const { return Internal::Control::GetLongPressGestureDetector(); }
-
-  void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual);
-  void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled );
-  void UnregisterVisual( Property::Index index );
-  void EnableVisual( Property::Index index, bool enabled );
-  bool IsVisualEnabled( Property::Index index );
-  int GetVisualCount();
-  Toolkit::Visual::Base GetVisual( Property::Index index );
-  Animation CreateTransition( const Toolkit::TransitionData& transition );
-  void DoAction( Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes );
-
-  static void SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value );
-
-  static Property::Value GetProperty( BaseObject* object, Dali::Property::Index propertyIndex );
+  inline void EnableGestureDetection(GestureType::Value type)
+  {
+    Internal::Control::EnableGestureDetection(type);
+  }
+  inline void DisableGestureDetection(GestureType::Value type)
+  {
+    Internal::Control::DisableGestureDetection(type);
+  }
+  inline PinchGestureDetector GetPinchGestureDetector() const
+  {
+    return Internal::Control::GetPinchGestureDetector();
+  }
+  inline PanGestureDetector GetPanGestureDetector() const
+  {
+    return Internal::Control::GetPanGestureDetector();
+  }
+  inline TapGestureDetector GetTapGestureDetector() const
+  {
+    return Internal::Control::GetTapGestureDetector();
+  }
+  inline LongPressGestureDetector GetLongPressGestureDetector() const
+  {
+    return Internal::Control::GetLongPressGestureDetector();
+  }
+
+  void                  RegisterVisual(Property::Index index, Toolkit::Visual::Base visual);
+  void                  RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, bool enabled);
+  void                  RegisterVisual(Property::Index index, Toolkit::Visual::Base visual, int depthIndex);
+  void                  UnregisterVisual(Property::Index index);
+  void                  EnableVisual(Property::Index index, bool enabled);
+  bool                  IsVisualEnabled(Property::Index index);
+  int                   GetVisualCount();
+  Toolkit::Visual::Base GetVisual(Property::Index index);
+  Animation             CreateTransition(const Toolkit::TransitionData& transition);
+  void                  DoAction(Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes);
+
+  static void SetProperty(BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value);
+
+  static Property::Value GetProperty(BaseObject* object, Dali::Property::Index propertyIndex);
 
   // Used to test signal connections
-  void CustomSlot1( Actor actor );
+  void CustomSlot1(Actor actor);
 
-  bool mCustomSlot1Called;
+  bool                                 mCustomSlot1Called;
   typedef std::vector<Property::Index> VisualIndices;
-  VisualIndices mRegisteredVisualIndices;
+  VisualIndices                        mRegisteredVisualIndices;
 
 protected:
-
   DummyControlImpl();
 
   ~DummyControlImpl() override;
@@ -127,7 +140,6 @@ protected:
 
 namespace Impl
 {
-
 /**
  * Cannot create an instance of Internal::Control, so use this dummy class for the implementation.
  * This class DOES override Internal::Control's behaviour.
@@ -135,38 +147,34 @@ namespace Impl
 class DummyControl : public Toolkit::DummyControlImpl
 {
 public:
-
-  typedef std::function<void( Size )> RelayoutCallbackFunc;
+  typedef std::function<void(Size)> RelayoutCallbackFunc;
 
   static Toolkit::DummyControl New();
 
-  void SetLayout( Property::Index visualIndex, Property::Map& map );
+  void SetLayout(Property::Index visualIndex, Property::Map& map);
 
-  void SetRelayoutCallback( RelayoutCallbackFunc callback );
+  void SetRelayoutCallback(RelayoutCallbackFunc callback);
 
 private:
-
   DummyControl();
 
   ~DummyControl() override;
 
 private: // From Internal::Control
-
   void OnInitialize() override;
   bool OnAccessibilityActivated() override;
-  bool OnAccessibilityValueChange( bool isIncrease ) override;
+  bool OnAccessibilityValueChange(bool isIncrease) override;
 
-  void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) override;
-  void OnPinch(const PinchGesture& pinch) override;
-  void OnPan(const PanGesture& pan) override;
-  void OnTap(const TapGesture& tap) override;
-  void OnLongPress(const LongPressGesture& longPress) override;
+  void    OnStyleChange(Toolkit::StyleManager styleManager, StyleChange::Type change) override;
+  void    OnPinch(const PinchGesture& pinch) override;
+  void    OnPan(const PanGesture& pan) override;
+  void    OnTap(const TapGesture& tap) override;
+  void    OnLongPress(const LongPressGesture& longPress) override;
   Vector3 GetNaturalSize() override;
-  bool OnKeyEvent(const KeyEvent& event) override;
+  bool    OnKeyEvent(const KeyEvent& event) override;
 
 private: // From CustomActorImpl
-
-  void OnSceneConnection( int depth ) override;
+  void OnSceneConnection(int depth) override;
   void OnSceneDisconnection() override;
   void OnChildAdd(Actor& child) override;
   void OnChildRemove(Actor& child) override;
@@ -174,39 +182,37 @@ private: // From CustomActorImpl
   void OnSizeAnimation(Animation& animation, const Vector3& targetSize) override;
   void OnKeyInputFocusGained() override;
   void OnKeyInputFocusLost() override;
-  void OnRelayout( const Vector2& size, RelayoutContainer& container ) override;
+  void OnRelayout(const Vector2& size, RelayoutContainer& container) override;
 
-  DALI_INTERNAL DummyControl( const DummyControl& );
-  DALI_INTERNAL DummyControl& operator=( const DummyControl& );
+  DALI_INTERNAL DummyControl(const DummyControl&);
+  DALI_INTERNAL DummyControl& operator=(const DummyControl&);
 
 public:
-
-  bool initializeCalled;
-  bool activatedCalled;
-  bool onAccValueChangeCalled;
-  bool themeChangeCalled;
-  bool fontChangeCalled;
-  bool pinchCalled;
-  bool panCalled;
-  bool tapCalled;
-  bool longPressCalled;
-  bool stageConnectionCalled;
-  bool stageDisconnectionCalled;
-  bool childAddCalled;
-  bool childRemoveCalled;
-  bool sizeSetCalled;
-  bool sizeAnimationCalled;
-  bool hoverEventCalled;
-  bool wheelEventCalled;
-  bool keyEventCalled;
-  bool keyInputFocusGained;
-  bool keyInputFocusLost;
+  bool       initializeCalled;
+  bool       activatedCalled;
+  bool       onAccValueChangeCalled;
+  bool       themeChangeCalled;
+  bool       fontChangeCalled;
+  bool       pinchCalled;
+  bool       panCalled;
+  bool       tapCalled;
+  bool       longPressCalled;
+  bool       stageConnectionCalled;
+  bool       stageDisconnectionCalled;
+  bool       childAddCalled;
+  bool       childRemoveCalled;
+  bool       sizeSetCalled;
+  bool       sizeAnimationCalled;
+  bool       hoverEventCalled;
+  bool       wheelEventCalled;
+  bool       keyEventCalled;
+  bool       keyInputFocusGained;
+  bool       keyInputFocusLost;
   static int constructorCount;
   static int destructorCount;
 
-  Property::Map mLayouts;
+  Property::Map        mLayouts;
   RelayoutCallbackFunc mRelayoutCallback;
-
 };
 
 } // namespace Impl
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 39d04e3..b8e1a03 100644 (file)
@@ -65,6 +65,11 @@ public:
   Dali::Clipboard::DataReceivedSignalType& DataReceivedSignal();
 
   /**
+   * @copydoc Dali::Clipboard::HasType()
+   */
+  bool HasType(const std::string& mimeType);
+
+  /**
    * @copydoc Dali::Clipboard::SetData()
    */
   bool SetData(const Dali::Clipboard::ClipData& clipData);
@@ -152,6 +157,11 @@ Dali::Clipboard::DataReceivedSignalType& Clipboard::DataReceivedSignal()
   return mDataReceivedSignal;
 }
 
+bool Clipboard::HasType(const std::string& mimeType)
+{
+  return mMimeType == mimeType ? true : false;
+}
+
 bool Clipboard::SetData(const Dali::Clipboard::ClipData& clipData)
 {
   mMimeType = clipData.GetMimeType();
index 7ad3187..4685e6d 100644 (file)
@@ -131,6 +131,13 @@ public:
   DataReceivedSignalType& DataReceivedSignal();
 
   /**
+   * @brief Check if there is data in the clipboard with a given mime type.
+   * @param[in] mimeType mime type to search for.
+   * @return bool true if there is data, otherwise false.
+   */
+  bool HasType(const std::string& mimeType);
+
+  /**
    * @brief Send the given data to the clipboard.
    * @param[in] clipData data to send to the clipboard
    * @return bool true if the internal clipboard sending was successful.
index 4535413..ba02bef 100644 (file)
@@ -481,7 +481,7 @@ int UtcDaliAnimatedImageVisualGetPropertyMap04(void)
 
   value = resultMap.Find(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, "totalFrameNumber");
   DALI_TEST_CHECK(value);
-  DALI_TEST_EQUALS(value->Get<int>(), 4, TEST_LOCATION);
+  DALI_TEST_EQUALS(value->Get<int>(), -1, TEST_LOCATION);
 
   value = resultMap.Find(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth");
   DALI_TEST_CHECK(value);
@@ -1994,7 +1994,6 @@ int UtcDaliAnimatedImageVisualDesiredSize(void)
   END_TEST;
 }
 
-
 int UtcDaliAnimatedImageVisualControlVisibilityChanged(void)
 {
   ToolkitTestApplication application;
@@ -2150,4 +2149,53 @@ int UtcDaliAnimatedImageVisualWindowVisibilityChanged(void)
   DALI_TEST_EQUALS(value->Get<int>(), 0, TEST_LOCATION);
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliAnimatedImageVisualFrameCountBeforeLoadingFinished(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedImageVisualFrameCountBeforeLoadingFinished");
+
+  Property::Map propertyMap;
+  propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_IMAGE)
+    .Add(ImageVisual::Property::URL, TEST_GIF_FILE_NAME)
+    .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  Property::Map resultMap1;
+  visual.CreatePropertyMap(resultMap1);
+  Property::Value* value1 = resultMap1.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
+  DALI_TEST_CHECK(value1);
+  DALI_TEST_EQUALS(value1->Get<int>(), -1, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+  DummyControl      actor     = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+  Property::Map resultMap2;
+  visual.CreatePropertyMap(resultMap2);
+  Property::Value* value2 = resultMap2.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
+  DALI_TEST_CHECK(value2);
+  DALI_TEST_EQUALS(value2->Get<int>(), -1, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+  Vector2 controlSize(20.f, 30.f);
+  actor.SetProperty(Actor::Property::SIZE, controlSize);
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - load & render a frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  Property::Map resultMap3;
+  visual.CreatePropertyMap(resultMap3);
+  Property::Value* value3 = resultMap3.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER);
+  DALI_TEST_CHECK(value3);
+  DALI_TEST_EQUALS(value3->Get<int>(), 4, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+  END_TEST;
+}
index 72a4966..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,16 +1551,16 @@ int UtcDaliAnimatedVectorImageVisualJumpTo(void)
 
   // Wait for animation finish
   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);
@@ -1417,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);
@@ -1446,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();
 
@@ -1473,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();
@@ -2388,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;
@@ -2445,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);
 
@@ -2490,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 4eb38b8..efc772d 100644 (file)
@@ -5580,6 +5580,86 @@ int UtcDaliImageViewTransitionEffect04(void)
   END_TEST;
 }
 
+int UtcDaliImageViewTransitionEffect05(void)
+{
+  tet_printf("Testing user's transition effect in ImageView \n");
+  ToolkitTestApplication application;
+
+  Property::Map map;
+  map["target"]      = "image";
+  map["property"]    = "opacity";
+  map["initialValue"] = 0.2f;
+  map["targetValue"] = 1.0f;
+  map["animator"]    = Property::Map()
+                      .Add("alphaFunction", "EASE_IN_OUT")
+                      .Add("timePeriod", Property::Map().Add("delay", 0.0f).Add("duration", 2.0f))
+                      .Add("animationType", "BETWEEN");
+
+  ImageView imageView = ImageView::New();
+  imageView.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 200.0f));
+  imageView.SetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT, true);
+  imageView.SetProperty(ImageView::Property::TRANSITION_EFFECT_OPTION, map);
+  imageView.SetImage(gImage_600_RGB);
+  application.GetScene().Add(imageView);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  Property::Value value;
+  value = imageView.GetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT);
+  bool transition;
+  DALI_TEST_CHECK(value.Get(transition));
+  DALI_TEST_CHECK(transition == true);
+
+  // Clear all cached
+  imageView.Unparent();
+  imageView.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliImageViewTransitionEffect06(void)
+{
+  tet_printf("Testing user's transition effect in ImageView \n");
+  ToolkitTestApplication application;
+
+  Property::Map map;
+  map["target"]      = "image";
+  map["property"]    = "opacity";
+  map["initialValue"] = 0.2f;
+  map["targetValue"] = 1.0f;
+  map["animator"]    = Property::Map()
+                      .Add("alphaFunction", "EASE_IN_OUT")
+                      .Add("timePeriod", Property::Map().Add("delay", 0.0f).Add("duration", 2.0f))
+                      .Add("animationType", "TO");
+
+  ImageView imageView = ImageView::New();
+  imageView.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 200.0f));
+  imageView.SetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT, true);
+  imageView.SetProperty(ImageView::Property::TRANSITION_EFFECT_OPTION, map);
+  imageView.SetImage(gImage_600_RGB);
+  application.GetScene().Add(imageView);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  Property::Value value;
+  value = imageView.GetProperty(ImageView::Property::ENABLE_TRANSITION_EFFECT);
+  bool transition;
+  DALI_TEST_CHECK(value.Get(transition));
+  DALI_TEST_CHECK(transition == true);
+
+  // Clear all cached
+  imageView.Unparent();
+  imageView.Reset();
+
+  END_TEST;
+}
+
+
+
 int UtcDaliImageViewImageLoadFailureAndReload01(void)
 {
   tet_infoline("Try to load invalid image first, and then reload after that image valid.");
index 0bd455b..319d4d4 100644 (file)
@@ -1384,6 +1384,93 @@ int UtcDaliImageVisualCustomWrapModePixelArea(void)
   END_TEST;
 }
 
+
+int UtcDaliImageVisualCustomWrapModePixelArea02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Request image visual with a Property::Map, test custom wrap mode and pixel area");
+
+  static std::vector<UniformData> customUniforms =
+    {
+      UniformData("pixelArea", Property::Type::VECTOR4),
+      UniformData("wrapMode", Property::Type::VECTOR2),
+    };
+
+  TestGraphicsController& graphics = application.GetGraphicsController();
+  graphics.AddCustomUniforms(customUniforms);
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK(factory);
+
+  // Test wrap mode with atlasing. Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+  const int     width  = 34;
+  const int     height = 34;
+  const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_SMALL_IMAGE_FILE_NAME);
+  propertyMap.Insert(ImageVisual::Property::DESIRED_WIDTH, width);
+  propertyMap.Insert(ImageVisual::Property::DESIRED_HEIGHT, height);
+  propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, false);
+  propertyMap.Insert(ImageVisual::Property::PIXEL_AREA, pixelArea);
+  propertyMap.Insert(ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT);
+  propertyMap.Insert(ImageVisual::Property::WRAP_MODE_V, WrapMode::CLAMP_TO_EDGE);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK(visual);
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+  texParameterTrace.Enable(true);
+
+  DummyControl      actor     = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(Control::CONTROL_PROPERTY_END_INDEX + 1, visual);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(2000, 2000));
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  application.GetScene().Add(actor);
+
+  // loading started
+  application.SendNotification();
+  application.Render();
+
+  // Wait image load complete.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(actor.GetRendererCount() == 1u);
+
+  DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+  // Following gl function should not be called
+  std::stringstream out;
+  out << std::hex << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+  DALI_TEST_CHECK(texParameterTrace.FindMethodAndParams("TexParameteri", out.str()));
+  out.str("");
+  out << std::hex << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_CLAMP_TO_EDGE;
+  DALI_TEST_CHECK(texParameterTrace.FindMethodAndParams("TexParameteri", out.str()));
+
+  // test the uniforms which used to handle the wrap mode
+  Renderer renderer = actor.GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+
+  Property::Value pixelAreaValue = renderer.GetProperty(renderer.GetPropertyIndex("pixelArea"));
+  DALI_TEST_EQUALS(pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION);
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector4>("pixelArea", pixelAreaUniform));
+  DALI_TEST_EQUALS(pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION);
+
+  actor.Unparent();
+  DALI_TEST_CHECK(actor.GetRendererCount() == 0u);
+
+  END_TEST;
+}
+
 int UtcDaliImageVisualCustomWrapModeNoAtlas(void)
 {
   ToolkitTestApplication application;
index bc75ce0..6a5745c 100644 (file)
@@ -117,6 +117,9 @@ const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP        = "enableGrabHan
 const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS           = "inputMethodSettings";
 const char* const PROPERTY_NAME_INPUT_FILTER                    = "inputFilter";
 
+const char* const PROPERTY_NAME_REMOVE_FRONT_INSET    = "removeFrontInset";
+const char* const PROPERTY_NAME_REMOVE_BACK_INSET     = "removeBackInset";
+
 const Vector4       PLACEHOLDER_TEXT_COLOR(0.8f, 0.8f, 0.8f, 0.8f);
 const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f); // The text highlight color.
 
@@ -634,6 +637,8 @@ int UtcDaliTextEditorGetPropertyP(void)
   DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_STRIKETHROUGH) == DevelTextEditor::Property::STRIKETHROUGH);
   DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_INPUT_STRIKETHROUGH) == DevelTextEditor::Property::INPUT_STRIKETHROUGH);
   DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_SELECTION_POPUP_STYLE) == DevelTextEditor::Property::SELECTION_POPUP_STYLE);
+  DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextEditor::Property::REMOVE_FRONT_INSET);
+  DALI_TEST_CHECK(editor.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextEditor::Property::REMOVE_BACK_INSET);
 
   END_TEST;
 }
@@ -1037,6 +1042,8 @@ int UtcDaliTextEditorSetPropertyP(void)
 
   outlineMapSet["color"] = Color::RED;
   outlineMapSet["width"] = 2.0f;
+  outlineMapSet["offset"] = Vector2(0.0f, 0.0f);
+  outlineMapSet["blurRadius"] = 0.0f;
 
   editor.SetProperty(TextEditor::Property::OUTLINE, outlineMapSet);
 
@@ -1265,6 +1272,18 @@ int UtcDaliTextEditorSetPropertyP(void)
   editor.SetProperty(DevelTextEditor::Property::MIN_LINE_SIZE, 50.f);
   DALI_TEST_EQUALS(editor.GetProperty<float>(DevelTextEditor::Property::MIN_LINE_SIZE), 50.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
 
+  // Check Remove Front/Back Inset Property
+  DALI_TEST_CHECK(editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_FRONT_INSET));
+  editor.SetProperty(DevelTextEditor::Property::REMOVE_FRONT_INSET, false);
+  DALI_TEST_CHECK(!editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_FRONT_INSET));
+
+  DALI_TEST_CHECK(editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_BACK_INSET));
+  editor.SetProperty(DevelTextEditor::Property::REMOVE_BACK_INSET, false);
+  DALI_TEST_CHECK(!editor.GetProperty<bool>(DevelTextEditor::Property::REMOVE_BACK_INSET));
+
+  application.SendNotification();
+  application.Render();
+
   END_TEST;
 }
 
@@ -6626,4 +6645,31 @@ int utcDaliTextEditorGetTextBoundingRectangle(void)
   TestTextGeometryUtils::CheckRectGeometryResult(textBoundingRectangle, expectedTextBoundingRectangle);
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int utcDaliTextEditorRemoveFrontInset(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorRemoveFrontInset");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK(editor);
+  application.GetScene().Add(editor);
+  application.SendNotification();
+  application.Render();
+  DevelTextEditor::SetRemoveFrontInset(editor, false);
+  DALI_TEST_CHECK(!DevelTextEditor::IsRemoveFrontInset(editor));
+  END_TEST;
+}
+int utcDaliTextEditorRemoveBackInset(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorRemoveBackInset");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK(editor);
+  application.GetScene().Add(editor);
+  application.SendNotification();
+  application.Render();
+  DevelTextEditor::SetRemoveBackInset(editor, false);
+  DALI_TEST_CHECK(!DevelTextEditor::IsRemoveBackInset(editor));
+  END_TEST;
+}
index ccc6bb3..d098f99 100644 (file)
@@ -115,6 +115,9 @@ const char* const PROPERTY_NAME_ENABLE_FONT_SIZE_SCALE          = "enableFontSiz
 const char* const PROPERTY_NAME_GRAB_HANDLE_COLOR               = "grabHandleColor";
 const char* const PROPERTY_NAME_INPUT_FILTER                    = "inputFilter";
 
+const char* const PROPERTY_NAME_REMOVE_FRONT_INSET    = "removeFrontInset";
+const char* const PROPERTY_NAME_REMOVE_BACK_INSET     = "removeBackInset";
+
 const Vector4       PLACEHOLDER_TEXT_COLOR(0.8f, 0.8f, 0.8f, 0.8f);
 const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f); // The text highlight color.
 
@@ -643,6 +646,8 @@ int UtcDaliTextFieldGetPropertyP(void)
   DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_STRIKETHROUGH) == DevelTextField::Property::STRIKETHROUGH);
   DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_INPUT_STRIKETHROUGH) == DevelTextField::Property::INPUT_STRIKETHROUGH);
   DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_SELECTION_POPUP_STYLE) == DevelTextField::Property::SELECTION_POPUP_STYLE);
+  DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextField::Property::REMOVE_FRONT_INSET);
+  DALI_TEST_CHECK(field.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextField::Property::REMOVE_BACK_INSET);
 
   END_TEST;
 }
@@ -1103,6 +1108,8 @@ int UtcDaliTextFieldSetPropertyP(void)
 
   outlineMapSet["color"] = Color::RED;
   outlineMapSet["width"] = 2.0f;
+  outlineMapSet["offset"] = Vector2(0.0f, 0.0f);
+  outlineMapSet["blurRadius"] = 0.0f;
 
   field.SetProperty(TextField::Property::OUTLINE, outlineMapSet);
 
@@ -1267,6 +1274,19 @@ int UtcDaliTextFieldSetPropertyP(void)
   application.SendNotification();
   application.Render();
 
+  // Check Remove Front/Back Inset Property
+  DALI_TEST_CHECK(field.GetProperty<bool>(DevelTextField::Property::REMOVE_FRONT_INSET));
+  field.SetProperty(DevelTextField::Property::REMOVE_FRONT_INSET, false);
+  DALI_TEST_CHECK(!field.GetProperty<bool>(DevelTextField::Property::REMOVE_FRONT_INSET));
+
+  DALI_TEST_CHECK(field.GetProperty<bool>(DevelTextField::Property::REMOVE_BACK_INSET));
+  field.SetProperty(DevelTextField::Property::REMOVE_BACK_INSET, false);
+  DALI_TEST_CHECK(!field.GetProperty<bool>(DevelTextField::Property::REMOVE_BACK_INSET));
+
+  application.SendNotification();
+  application.Render();
+
+
   END_TEST;
 }
 
@@ -3244,7 +3264,56 @@ int utcDaliTextFieldEvent08(void)
     event.AddPoint(GetPointUpInside(position));
     application.ProcessEvent(event);
   }
-  DALI_TEST_EQUALS(field.GetProperty<std::string>(TextEditor::Property::TEXT), std::string("testTextFieldEvent"), TEST_LOCATION);
+  DALI_TEST_EQUALS(field.GetProperty<std::string>(TextField::Property::TEXT), std::string("testTextFieldEvent"), TEST_LOCATION);
+
+  Dali::Clipboard::ClipData htmlData("application/xhtml+xml", "testTextFieldEventHtml");
+  clipboard.SetData(htmlData);
+
+  field.SetProperty(TextField::Property::TEXT, "");
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Long Press
+  TestGenerateLongPress(application, 1.0f, 25.0f, 20);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Wait(application, 500);
+
+  TestEndLongPress(application, 1.0f, 25.0f, 520);
+
+  // Long Press
+  TestGenerateLongPress(application, 1.0f, 25.0f, 600);
+
+  // Render and notify
+  application.Render();
+
+  Wait(application, 500);
+
+  stage = application.GetScene();
+  layer = stage.GetRootLayer();
+  actor = layer.FindChildByName("optionPaste");
+
+  if(actor)
+  {
+    Vector3 worldPosition = actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_POSITION);
+    Vector2 halfStageSize = stage.GetSize() / 2.0f;
+    Vector2 position(worldPosition.x + halfStageSize.width, worldPosition.y + halfStageSize.height);
+
+    Dali::Integration::TouchEvent event;
+    event = Dali::Integration::TouchEvent();
+    event.AddPoint(GetPointDownInside(position));
+    application.ProcessEvent(event);
+
+    event = Dali::Integration::TouchEvent();
+    event.AddPoint(GetPointUpInside(position));
+    application.ProcessEvent(event);
+  }
+  DALI_TEST_EQUALS(field.GetProperty<std::string>(TextField::Property::TEXT), std::string("testTextFieldEventHtml"), TEST_LOCATION);
 
   END_TEST;
 }
@@ -6083,4 +6152,40 @@ int utcDaliTextFieldDecoratorColor(void)
   application.Render();
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int utcDaliTextFieldRemoveFrontInset(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldRemoveFrontInset");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK(field);
+
+  application.GetScene().Add(field);
+  application.SendNotification();
+  application.Render();
+
+  DevelTextField::SetRemoveFrontInset(field, false);
+  DALI_TEST_CHECK(!DevelTextField::IsRemoveFrontInset(field));
+
+  END_TEST;
+}
+
+int utcDaliTextFieldRemoveBackInset(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldRemoveBackInset");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK(field);
+
+  application.GetScene().Add(field);
+  application.SendNotification();
+  application.Render();
+
+  DevelTextField::SetRemoveBackInset(field, false);
+  DALI_TEST_CHECK(!DevelTextField::IsRemoveBackInset(field));
+
+  END_TEST;
+}
index dd0b690..aed1457 100644 (file)
@@ -82,6 +82,7 @@ const char* const PROPERTY_NAME_ANCHOR_CLICKED_COLOR = "anchorClickedColor";
 
 const char* const PROPERTY_NAME_REMOVE_FRONT_INSET    = "removeFrontInset";
 const char* const PROPERTY_NAME_REMOVE_BACK_INSET     = "removeBackInset";
+const char* const PROPERTY_NAME_REMOVE_CUTOUT         = "cutout";
 
 const std::string  DEFAULT_FONT_DIR("/resources/fonts");
 const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
@@ -365,6 +366,7 @@ int UtcDaliToolkitTextLabelGetPropertyP(void)
   DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_CLICKED_COLOR) == DevelTextLabel::Property::ANCHOR_CLICKED_COLOR);
   DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextLabel::Property::REMOVE_FRONT_INSET);
   DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextLabel::Property::REMOVE_BACK_INSET);
+  DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_CUTOUT) == DevelTextLabel::Property::CUTOUT);
 
   END_TEST;
 }
@@ -952,6 +954,8 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
 
   outlineMapSet["color"] = Color::RED;
   outlineMapSet["width"] = 2.0f;
+  outlineMapSet["offset"] = Vector2(2.0f, 2.0f);
+  outlineMapSet["blurRadius"] = 3.0f;
   label.SetProperty(TextLabel::Property::OUTLINE, outlineMapSet);
 
   outlineMapGet = label.GetProperty<Property::Map>(TextLabel::Property::OUTLINE);
@@ -961,11 +965,14 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
   outlineMapSet.Clear();
   outlineMapSet[Toolkit::DevelText::Outline::Property::COLOR] = Color::BLUE;
   outlineMapSet[Toolkit::DevelText::Outline::Property::WIDTH] = 3.0f;
+  outlineMapSet[Toolkit::DevelText::Outline::Property::OFFSET] = Vector2(3.0f, 3.0f);
+  outlineMapSet[Toolkit::DevelText::Outline::Property::BLUR_RADIUS] = 4.0f;
+
   label.SetProperty(TextLabel::Property::OUTLINE, outlineMapSet);
 
   outlineMapGet = label.GetProperty<Property::Map>(TextLabel::Property::OUTLINE);
   DALI_TEST_EQUALS(outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION);
-  std::vector<std::string> outlineIndicesConversionTable = {"color", "width"};
+  std::vector<std::string> outlineIndicesConversionTable = {"color", "width", "offset", "blurRadius"};
   DALI_TEST_EQUALS(DaliTestCheckMaps(outlineMapGet, outlineMapSet, outlineIndicesConversionTable), true, TEST_LOCATION);
 
   // Check the background property
@@ -1036,6 +1043,14 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
   application.SendNotification();
   application.Render();
 
+  // Check cutout Property
+  DALI_TEST_CHECK(!label.GetProperty<bool>(DevelTextLabel::Property::CUTOUT));
+  label.SetProperty(DevelTextLabel::Property::CUTOUT, true);
+  DALI_TEST_CHECK(label.GetProperty<bool>(DevelTextLabel::Property::CUTOUT));
+
+  application.SendNotification();
+  application.Render();
+
   END_TEST;
 }
 
@@ -1789,6 +1804,16 @@ int UtcDaliToolkitTextLabelColorComponents(void)
 
   DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION); // Rendering should be skipped
 
+  label.SetProperty(DevelTextLabel::Property::CUTOUT, true);
+
+  drawTrace.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION); // When cutout is enabled, should not be skipped
+
+  label.SetProperty(DevelTextLabel::Property::CUTOUT, false);
   label.SetProperty(TextLabel::Property::TEXT_COLOR, Color::RED);
 
   drawTrace.Reset();
@@ -1817,6 +1842,8 @@ int UtcDaliToolkitTextlabelTextStyle01(void)
 
   outlineMapSet["color"] = Color::BLUE;
   outlineMapSet["width"] = 2.0f;
+  outlineMapSet["offset"] = "2 2";
+  outlineMapSet["blurRadius"] = "3";
   label.SetProperty(TextLabel::Property::OUTLINE, outlineMapSet);
 
   application.SendNotification();
index 5f7d114..e2659ff 100644 (file)
@@ -1290,7 +1290,7 @@ int UtcDaliVisualGetPropertyMap10(void)
   propertyMap.Insert("underline", underlineMapSet.Add("enable", true).Add("color", Color::GREEN).Add("height", 1).Add("type", Text::Underline::Type::SOLID).Add("dashWidth", 2).Add("dashGap", 1));
 
   Property::Map outlineMapSet;
-  propertyMap.Insert("outline", outlineMapSet.Add("color", Color::YELLOW).Add("width", 1));
+  propertyMap.Insert("outline", outlineMapSet.Add("color", Color::YELLOW).Add("width", 1).Add("offset", Vector2(2.0f, 2.0f)).Add("blurRadius", 3.0f));
 
   Property::Map backgroundMapSet;
   propertyMap.Insert("textBackground", backgroundMapSet.Add("enable", true).Add("color", Color::CYAN));
@@ -3762,11 +3762,11 @@ int UtcDaliRegisterVisualOrder(void)
   dummyImpl.RegisterVisual(DummyControl::Property::FOCUS_VISUAL, focusVisual);
   DALI_TEST_CHECK(focusVisual.GetDepthIndex() > foregroundVisual.GetDepthIndex());
 
-  tet_infoline("Set depth index on a new visual before registering, the depth index should not have been changed");
+  tet_infoline("Set depth index on a new visual before registering, the depth index should not have been changed, and be clampled");
   Visual::Base labelVisual = factory.CreateVisual(propertyMap);
-  labelVisual.SetDepthIndex(-2000);
+  labelVisual.SetDepthIndex(static_cast<int>(Toolkit::DepthIndex::MINIMUM_DEPTH_INDEX) - 100);
   dummyImpl.RegisterVisual(DummyControl::Property::LABEL_VISUAL, labelVisual);
-  DALI_TEST_EQUALS(labelVisual.GetDepthIndex(), -2000, TEST_LOCATION);
+  DALI_TEST_EQUALS(labelVisual.GetDepthIndex(), static_cast<int>(Toolkit::DepthIndex::MINIMUM_DEPTH_INDEX), TEST_LOCATION);
 
   tet_infoline("Replace visual, the depth index should be the same as what was previously set");
   const int    testVisual2DepthIndex  = testVisual2.GetDepthIndex();
@@ -3775,11 +3775,11 @@ int UtcDaliRegisterVisualOrder(void)
   dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL2, testVisual2Replacement);
   DALI_TEST_EQUALS(testVisual2Replacement.GetDepthIndex(), testVisual2DepthIndex, TEST_LOCATION);
 
-  tet_infoline("Replace visual and set a depth index on the replacement, the depth index of the replacement should be honoured");
+  tet_infoline("Replace visual and set a depth index on the replacement, the depth index of the replacement should be honoured, and be clampled");
   Visual::Base anotherTestVisual2Replacement = factory.CreateVisual(propertyMap);
-  anotherTestVisual2Replacement.SetDepthIndex(2000);
+  anotherTestVisual2Replacement.SetDepthIndex(static_cast<int>(Toolkit::DepthIndex::MAXIMUM_DEPTH_INDEX) + 100);
   dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL2, anotherTestVisual2Replacement);
-  DALI_TEST_EQUALS(anotherTestVisual2Replacement.GetDepthIndex(), 2000, TEST_LOCATION);
+  DALI_TEST_EQUALS(anotherTestVisual2Replacement.GetDepthIndex(), static_cast<int>(Toolkit::DepthIndex::MAXIMUM_DEPTH_INDEX), TEST_LOCATION);
 
   dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
   application.GetScene().Add(dummyControl);
@@ -3806,7 +3806,7 @@ int UtcDaliRegisterVisualOrder02(void)
 
   dummyControl.SetProperty(Control::Property::BACKGROUND, propertyMap);
 
-  const int TEST_VISUAL_1_DEPTH_INDEX = 0;
+  const int TEST_VISUAL_1_DEPTH_INDEX = static_cast<int>(Toolkit::DepthIndex::CONTENT);
   tet_printf("Register visual, should have depth index of %d\n", TEST_VISUAL_1_DEPTH_INDEX);
   Visual::Base testVisual1 = factory.CreateVisual(propertyMap);
   dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, testVisual1);
@@ -3815,7 +3815,14 @@ int UtcDaliRegisterVisualOrder02(void)
   tet_printf("Register another visual, should have a depth index greater than previous(%d)\n", TEST_VISUAL_1_DEPTH_INDEX);
   Visual::Base testVisual2 = factory.CreateVisual(propertyMap);
   dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL2, testVisual2);
-  DALI_TEST_CHECK(testVisual2.GetDepthIndex() > testVisual1.GetDepthIndex());
+  DALI_TEST_GREATER(testVisual2.GetDepthIndex(), testVisual1.GetDepthIndex(), TEST_LOCATION);
+
+  const int TEST_VISUAL_2_DEPTH_INDEX = testVisual2.GetDepthIndex();
+
+  tet_printf("Register other visual, should have a depth index greater than previous(%d)\n", TEST_VISUAL_2_DEPTH_INDEX);
+  Visual::Base testVisual3 = factory.CreateVisual(propertyMap);
+  dummyImpl.RegisterVisual(DummyControl::Property::FOREGROUND_VISUAL, testVisual3, Toolkit::DepthIndex::AUTO_INDEX);
+  DALI_TEST_GREATER(testVisual3.GetDepthIndex(), testVisual2.GetDepthIndex(), TEST_LOCATION);
 
   dummyControl.SetProperty(Actor::Property::SIZE, Vector2(200.f, 200.f));
   application.GetScene().Add(dummyControl);
index 8c9b9b3..7fc62c1 100644 (file)
@@ -306,6 +306,7 @@ SceneView::SceneView()
   mSkybox(),
   mSkyboxOrientation(Quaternion()),
   mSkyboxIntensity(1.0f),
+  mLightObservers(),
   mShaderManager(new Scene3D::Loader::ShaderManager())
 {
 }
@@ -437,7 +438,7 @@ void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item)
   {
     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
     item->NotifyShadowMapTexture(mShadowTexture);
-    mItems.push_back(item);
+    mLightObservers.PushBack(item);
   }
 }
 
@@ -445,13 +446,10 @@ void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item)
 {
   if(item)
   {
-    for(uint32_t i = 0; i < mItems.size(); ++i)
+    auto iter = mLightObservers.Find(item);
+    if(iter != mLightObservers.End())
     {
-      if(mItems[i] == item)
-      {
-        mItems.erase(mItems.begin() + i);
-        break;
-      }
+      mLightObservers.Erase(iter);
     }
   }
 }
@@ -566,7 +564,7 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st
 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
 {
   mIblScaleFactor = scaleFactor;
-  for(auto&& item : mItems)
+  for(auto&& item : mLightObservers)
   {
     if(item)
     {
@@ -693,7 +691,7 @@ void SceneView::RemoveShadow(Scene3D::Light light)
   mShadowLight.Reset();
 
   mShadowTexture.Reset();
-  for(auto&& item : mItems)
+  for(auto&& item : mLightObservers)
   {
     if(item)
     {
@@ -1020,7 +1018,7 @@ void SceneView::OnSceneConnection(int depth)
 
 void SceneView::OnSceneDisconnection()
 {
-  mItems.clear();
+  mLightObservers.Clear();
 
   Window window = mWindow.GetHandle();
   if(window)
@@ -1369,7 +1367,7 @@ void SceneView::OnIblLoadComplete()
 
 void SceneView::NotifyImageBasedLightTextureChange()
 {
-  for(auto&& item : mItems)
+  for(auto&& item : mLightObservers)
   {
     if(item)
     {
@@ -1411,7 +1409,7 @@ void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
     DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
     mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
 
-    for(auto&& item : mItems)
+    for(auto&& item : mLightObservers)
     {
       if(item)
       {
index 3d8c639..29661ef 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali-toolkit/internal/visuals/image/image-visual.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/integration-api/ordered-set.h>
 #include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/adaptor-framework/window.h>
@@ -434,21 +435,22 @@ private:
 
   /////////////////////////////////////////////////////////////
   // FrameBuffer and Rendertask to render child objects as a 3D Scene
-  Dali::WeakHandle<Dali::Window>                 mWindow;
-  Integration::SceneHolder                       mSceneHolder;
-  CameraActor                                    mDefaultCamera;
-  CameraActor                                    mSelectedCamera;
-  std::vector<CameraActor>                       mCameras;
-  std::vector<Scene3D::Internal::LightObserver*> mItems;
-  Dali::FrameBuffer                              mFrameBuffer;
-  Dali::Texture                                  mTexture;
-  Dali::RenderTask                               mRenderTask;
-  Layer                                          mRootLayer;
-  int32_t                                        mWindowOrientation;
-  Dali::Actor                                    mSkybox;
-  Quaternion                                     mSkyboxOrientation;
-  float                                          mSkyboxIntensity{1.0f};
-  uint8_t                                        mFrameBufferMultiSamplingLevel{0u};
+  Dali::WeakHandle<Dali::Window> mWindow;
+  Integration::SceneHolder       mSceneHolder;
+  CameraActor                    mDefaultCamera;
+  CameraActor                    mSelectedCamera;
+  std::vector<CameraActor>       mCameras;
+  Dali::FrameBuffer              mFrameBuffer;
+  Dali::Texture                  mTexture;
+  Dali::RenderTask               mRenderTask;
+  Layer                          mRootLayer;
+  int32_t                        mWindowOrientation;
+  Dali::Actor                    mSkybox;
+  Quaternion                     mSkyboxOrientation;
+  float                          mSkyboxIntensity{1.0f};
+  uint8_t                        mFrameBufferMultiSamplingLevel{0u};
+
+  Dali::Integration::OrderedSet<Scene3D::Internal::LightObserver, false> mLightObservers; ///< The set of items to be notified when light properties change. (not owned)
 
   bool     mWindowSizeChanged{false};
   uint32_t mWindowWidth{0};
index c0a873d..5218700 100644 (file)
@@ -1,3 +1,4 @@
+#define MORPH defined(MORPH_POSITION) || defined(MORPH_NORMAL) || defined(MORPH_TANGENT)
 
 #define ADD_EXTRA_SKINNING_ATTRIBUTES
 #define ADD_EXTRA_WEIGHTS
index 8f2bc57..0b8dc93 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -85,7 +85,7 @@ void BufferDefinition::LoadBuffer()
   {
     if(mUri.find(EMBEDDED_DATA_PREFIX.data()) == 0 && mUri.find(EMBEDDED_DATA_APPLICATION_MEDIA_TYPE.data(), EMBEDDED_DATA_PREFIX.length()) == EMBEDDED_DATA_PREFIX.length())
     {
-      uint32_t position = mUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_APPLICATION_MEDIA_TYPE.length());
+      auto position = mUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_APPLICATION_MEDIA_TYPE.length());
       if(position != std::string::npos)
       {
         position += EMBEDDED_DATA_BASE64_ENCODING_TYPE.length();
index 52028bf..b61005b 100644 (file)
@@ -97,7 +97,7 @@ Dali::PixelData LoadImageResource(const std::string& resourcePath,
   }
   else if(textureDefinition.mImageUri.find(EMBEDDED_DATA_PREFIX.data()) == 0 && textureDefinition.mImageUri.find(EMBEDDED_DATA_IMAGE_MEDIA_TYPE.data(), EMBEDDED_DATA_PREFIX.length()) == EMBEDDED_DATA_PREFIX.length())
   {
-    uint32_t position = textureDefinition.mImageUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_IMAGE_MEDIA_TYPE.length());
+    auto position = textureDefinition.mImageUri.find(EMBEDDED_DATA_BASE64_ENCODING_TYPE.data(), EMBEDDED_DATA_PREFIX.length() + EMBEDDED_DATA_IMAGE_MEDIA_TYPE.length());
     if(position != std::string::npos)
     {
       position += EMBEDDED_DATA_BASE64_ENCODING_TYPE.length();
index 8788ade..7e6981b 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)
@@ -192,7 +235,7 @@ Dali::Accessibility::States ControlAccessible::CalculateStates()
   states[State::FOCUSABLE]     = self.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE);
   states[State::FOCUSED]       = Toolkit::KeyboardFocusManager::Get().GetCurrentFocusActor() == self;
   states[State::HIGHLIGHTABLE] = self.GetProperty<bool>(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE);
-  states[State::HIGHLIGHTED]   = GetCurrentlyHighlightedActor() == self;
+  states[State::HIGHLIGHTED]   = IsHighlighted();
   states[State::ENABLED]       = true;
   states[State::SENSITIVE]     = (Dali::DevelActor::IsHittable(self) && Dali::DevelActor::GetTouchRequired(self));
   states[State::VISIBLE]       = self.GetProperty<bool>(Actor::Property::VISIBLE);
@@ -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())
   {
@@ -373,18 +425,16 @@ bool ControlAccessible::GrabHighlight()
 
 bool ControlAccessible::ClearHighlight()
 {
-  Dali::Actor self = Self();
-
   if(!Dali::Accessibility::IsUp())
   {
     return false;
   }
 
-  if(GetCurrentlyHighlightedActor() == self)
+  if(IsHighlighted())
   {
     UnregisterPropertySetSignal();
     UnregisterPositionPropertyNotification();
-    self.Remove(mCurrentHighlightActor.GetHandle());
+    Self().Remove(mCurrentHighlightActor.GetHandle());
     mCurrentHighlightActor = {};
     SetCurrentlyHighlightedActor({});
     EmitHighlighted(false);
index 3aa0c9f..e66c4ee 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_DEVEL_CONTROL_DEPTH_INDEX_RANGES_H
 
 /*
- * Copyright (c) 2020 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.
@@ -30,25 +30,41 @@ namespace DepthIndex
 // The negative value for background effect and background has been
 // chosen so that newer controls can have content without setting
 // depth index, and go in front of native controls with a background.
-// This backround negative value means that the highest possible value
-// is SIBLING_ORDER_MULTIPLIER-BACKGROUND_EFFECT-1.  The divisor of
-// 100 ensures the range fits within the sibling order range, and has
-// enough gaps to allow Control Authors to use other intermediate depths.
+// The lowest possible value is MINIMUM_DEPTH_INDEX, and highest possible
+// value is MAXIMUM_DEPTH_INDEX. The divisor of 10 ensures the range fits
+// within the sibling order range, and has enough gaps to allow Control
+// Authors to use other intermediate depths.
+//
+// Note : AUTO_INDEX is special value. It means that the depth index will be
+// automatically assigned when we register visual into the control.
+// Other values will be clamped to the range.
 
 enum Ranges
 {
-  BACKGROUND_EFFECT = -2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100,
-  BACKGROUND        = -1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100,
-  CONTENT           = 0,
-  DECORATION        = 1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100,
-  FOREGROUND_EFFECT = 2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 100
+  MINIMUM_DEPTH_INDEX = -5 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10 + 1,
+  BACKGROUND_EFFECT   = -2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+  BACKGROUND          = -1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+  CONTENT             = 0,
+  DECORATION          = 1 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+  FOREGROUND_EFFECT   = 2 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+  MAXIMUM_DEPTH_INDEX = 5 * DevelLayer::SIBLING_ORDER_MULTIPLIER / 10,
+
+  AUTO_INDEX = MINIMUM_DEPTH_INDEX - 1, ///< Special value to indicate that the depth index should be automatically calculated.
+                                        ///  If visual replaced by another visual, the depth index of the new visual will be set to previous visual.
+                                        ///  Otherwise, depth index will be set as the maximum depth index + 1
+                                        ///  what given control already has, or CONTENT if no visuals.
 };
 
 static_assert((unsigned int)DevelLayer::ACTOR_DEPTH_MULTIPLIER > (unsigned int)DevelLayer::SIBLING_ORDER_MULTIPLIER);
+static_assert(MINIMUM_DEPTH_INDEX < BACKGROUND_EFFECT);
 static_assert(BACKGROUND_EFFECT < BACKGROUND);
 static_assert(BACKGROUND < CONTENT);
 static_assert(CONTENT < DECORATION);
 static_assert(DECORATION < FOREGROUND_EFFECT);
+static_assert(FOREGROUND_EFFECT < MAXIMUM_DEPTH_INDEX);
+
+// AUTO_INDEX should not be inside of the valid range.
+static_assert(!(MINIMUM_DEPTH_INDEX <= AUTO_INDEX && AUTO_INDEX <= MAXIMUM_DEPTH_INDEX));
 
 } // namespace DepthIndex
 
index fe2548f..465041a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_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.
@@ -236,8 +236,7 @@ enum
  *
  * @note Derived class should not call visual.SetOnScene(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
  *       Use below API with enabled set to false if derived class wishes to control when visual is staged.
- * @note If the depth-index is not set on the visual, then it is set to be above the currently registered visuals.
- * @note If replacing a visual, then the depth-index of the visual being replaced is used for the visual.
+ * @note depth-index be used to Dali::Toolkit::DepthIndex::Ranges::AUTO_INDEX.
  */
 DALI_TOOLKIT_API void RegisterVisual(Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual);
 
@@ -247,7 +246,9 @@ DALI_TOOLKIT_API void RegisterVisual(Internal::Control& control, Dali::Property:
  * @param[in] control The control
  * @param[in] index The Property index of the visual, used to reference visual
  * @param[in] visual The visual to register
- * @param[in] depthIndex The visual's depth-index is set to this
+ * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+ *                       the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+ *                       Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
  *
  * @note Derived class should not call visual.SetOnScene(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
  *       Use below API with enabled set to false if derived class wishes to control when visual is staged.
@@ -265,8 +266,7 @@ DALI_TOOLKIT_API void RegisterVisual(Internal::Control& control, Dali::Property:
  * @param[in] visual The visual to register
  * @param[in] enabled false if derived class wants to control when visual is set on stage.
  *
- * @note If the depth-index is not set on the visual, then it is set to be above the currently registered visuals.
- * @note If replacing a visual, then the depth-index of the visual being replaced is used for the visual.
+ * @note depth-index be used to Dali::Toolkit::DepthIndex::Ranges::AUTO_INDEX.
  *
  * @see EnableVisual()
  */
@@ -279,7 +279,9 @@ DALI_TOOLKIT_API void RegisterVisual(Internal::Control& control, Dali::Property:
  * @param[in] index The Property index of the visual, used to reference visual
  * @param[in] visual The visual to register
  * @param[in] enabled false if derived class wants to control when visual is set on stage.
- * @param[in] depthIndex The visual's depth-index is set to this
+ * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+ *                       the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+ *                       Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
  *
  * @see EnableVisual()
  * @see Visual::Base::GetDepthIndex()
index eeef11f..84a80b7 100644 (file)
@@ -115,6 +115,26 @@ void PasteText(TextEditor textEditor)
   GetImpl(textEditor).PasteText();
 }
 
+void SetRemoveFrontInset(TextEditor textEditor, const bool remove)
+{
+  GetImpl(textEditor).SetRemoveFrontInset(remove);
+}
+
+bool IsRemoveFrontInset(TextEditor textEditor)
+{
+  return GetImpl(textEditor).IsRemoveFrontInset();
+}
+
+void SetRemoveBackInset(TextEditor textEditor, const bool remove)
+{
+  GetImpl(textEditor).SetRemoveBackInset(remove);
+}
+
+bool IsRemoveBackInset(TextEditor textEditor)
+{
+  return GetImpl(textEditor).IsRemoveBackInset();
+}
+
 } // namespace DevelTextEditor
 
 } // namespace Toolkit
index 9aab35f..1831327 100644 (file)
@@ -325,6 +325,18 @@ enum Type
    * @see Dali::Toolkit::TextSelectionPopup::Property
    */
   SELECTION_POPUP_STYLE,
+
+  /**
+   * @brief Whether to trim the xBearing of first glyph of the text.
+   * @details Name "removeFrontInset", type Property::BOOLEAN.
+   */
+  REMOVE_FRONT_INSET,
+
+  /**
+   * @brief Whether to trim the advance of last glyph of the text.
+   * @details Name "removeBackInset", type Property::BOOLEAN.
+   */
+  REMOVE_BACK_INSET,
 };
 
 } // namespace Property
@@ -575,6 +587,39 @@ DALI_TOOLKIT_API std::string CutText(TextEditor textEditor);
  */
 DALI_TOOLKIT_API void PasteText(TextEditor textEditor);
 
+/**
+ * @brief Set removing front inset to text label.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @param[in] remove Whether front inset of text label has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveFrontInset(TextEditor textEditor, const bool remove);
+
+/**
+ * @brief Whether front inset of text label is removed or not.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @return True if the front inset of text label is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveFrontInset(TextEditor textEditor);
+
+/**
+ * @brief Set removing back inset to text label.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @param[in] remove Whether back inset of text label has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveBackInset(TextEditor textEditor, const bool remove);
+
+/**
+ * @brief Whether back inset of text label is removed or not.
+ *
+ * @param[in] textEditor The instance of TextLabel.
+ * @return True if the back inset of text label is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveBackInset(TextEditor textEditor);
+
+
 } // namespace DevelTextEditor
 
 } // namespace Toolkit
index 2105756..7f19475 100644 (file)
@@ -105,6 +105,26 @@ void PasteText(TextField textField)
   GetImpl(textField).PasteText();
 }
 
+void SetRemoveFrontInset(TextField textField, const bool remove)
+{
+  GetImpl(textField).SetRemoveFrontInset(remove);
+}
+
+bool IsRemoveFrontInset(TextField textField)
+{
+  return GetImpl(textField).IsRemoveFrontInset();
+}
+
+void SetRemoveBackInset(TextField textField, const bool remove)
+{
+  GetImpl(textField).SetRemoveBackInset(remove);
+}
+
+bool IsRemoveBackInset(TextField textField)
+{
+  return GetImpl(textField).IsRemoveBackInset();
+}
+
 } // namespace DevelTextField
 
 } // namespace Toolkit
index a061819..8d368ee 100644 (file)
@@ -249,6 +249,18 @@ enum
    * @see Dali::Toolkit::TextSelectionPopup::Property
    */
   SELECTION_POPUP_STYLE,
+
+  /**
+   * @brief Whether to trim the xBearing of first glyph of the text.
+   * @details Name "removeFrontInset", type Property::BOOLEAN.
+   */
+  REMOVE_FRONT_INSET,
+
+  /**
+   * @brief Whether to trim the advance of last glyph of the text.
+   * @details Name "removeBackInset", type Property::BOOLEAN.
+   */
+  REMOVE_BACK_INSET,
 };
 
 } // namespace Property
@@ -474,6 +486,38 @@ DALI_TOOLKIT_API std::string CutText(TextField textField);
  */
 DALI_TOOLKIT_API void PasteText(TextField textField);
 
+/**
+ * @brief Set removing front inset to TextField.
+ *
+ * @param[in] textField The instance of TextField.
+ * @param[in] remove Whether front inset of TextField has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveFrontInset(TextField textField, const bool remove);
+
+/**
+ * @brief Whether front inset of TextField is removed or not.
+ *
+ * @param[in] textField The instance of TextField.
+ * @return True if the front inset of TextField is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveFrontInset(TextField textField);
+
+/**
+ * @brief Set removing back inset to TextField.
+ *
+ * @param[in] textField The instance of TextField.
+ * @param[in] remove Whether back inset of TextField has to be removed or not.
+ */
+DALI_TOOLKIT_API void SetRemoveBackInset(TextField textField, const bool remove);
+
+/**
+ * @brief Whether back inset of TextField is removed or not.
+ *
+ * @param[in] textField The instance of TextField.
+ * @return True if the back inset of TextField is removed.
+ */
+DALI_TOOLKIT_API bool IsRemoveBackInset(TextField textField);
+
 } // namespace DevelTextField
 
 } // namespace Toolkit
index ed2e5d9..4c00662 100644 (file)
@@ -230,6 +230,12 @@ enum Type
    * @details Name "removeBackInset", type Property::BOOLEAN.
    */
   REMOVE_BACK_INSET,
+
+  /**
+   * @brief Whether to make the elements transparent, such as background or outline behind the text.
+   * @details Name "cutout", type Property::BOOLEAN.
+   */
+  CUTOUT,
 };
 
 } // namespace Property
index e3641f6..687897b 100644 (file)
@@ -137,7 +137,21 @@ enum
    * @details Name "width", type Property::STRING or Property::FLOAT i.e. "1.0" or 1.f
    * @note Optional. If not provided then the outline is not enabled.
    */
-  WIDTH
+  WIDTH,
+
+  /**
+   * @brief The offset in pixels of the outline.
+   * @details Name "offset", type Property::STRING or Property::VECTOR2. i.e "3.0 3.0" or Vector2( 3.f, 3.f )
+   * @note Optional. If not provided then the outline is not enabled.
+   */
+  OFFSET,
+
+  /**
+   * @brief The radius of the Gaussian blur for the outline.
+   * @details Name "blurRadius", type Property::STRING or Property::FLOAT. i.e "5.0" or 5.f
+   * @note Optional. If not provided then the outline is not enabled.
+   */
+  BLUR_RADIUS
 };
 
 } // namespace Property
index 14538fd..2a43766 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_RANGE_H
 
 /*
- * Copyright (c) 2022 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.
@@ -144,16 +144,6 @@ public: //Methods
 
 } // namespace Toolkit
 
-// Allow Range to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Range> : public BasicTypes<Dali::Toolkit::Text::Range>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_TEXT_RANGE_H
index e3f7f29..5769965 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_BASE_SPAN_H
 
 /*
- * Copyright (c) 2022 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.
@@ -122,16 +122,6 @@ public: // Not intended for application developers
 
 } // namespace Toolkit
 
-// Allow BaseSpan to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::BaseSpan> : public BasicTypes<Dali::Toolkit::Text::BaseSpan>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_TEXT_BASE_SPAN_H
index 3b03dbe..dc31868 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef DALI_TOOLKIT_VISUAL_BASE_H
 #define DALI_TOOLKIT_VISUAL_BASE_H
 /*
- * Copyright (c) 2020 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.
@@ -167,14 +167,20 @@ public:
    * @brief Set the depth index of this visual.
    *
    * Depth-index controls draw-order for overlapping visuals.
-   * Visuals with higher depth indices are rendered in front of other visual with smaller values
+   * Visuals with higher depth indices are rendered in front of other visual with smaller values.
+   *
+   * @note The value of index will be clamped between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and
+   * DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
+   * @note If we call this API at least 1 time, we cannot set as DepthIndex::AUTO_INDEX after.
    *
    * @param[in] index The depth index of this visual.
    */
   void SetDepthIndex(int index);
 
   /**
-   * @brief Get the depth index of this visual
+   * @brief Get the depth index of this visual which clamped between
+   * DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
+   * Or DepthIndex::Ranges::AUTO_INDEX if we never set depth index before.
    *
    * @return The depth index of this visual.
    */
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 aa23c76..3f7e73e 100644 (file)
@@ -162,9 +162,17 @@ void TreeNodeManipulator::RemoveChildren()
 {
   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
 
-  DeleteNodesWithoutSelf otherDeletor(mNode);
+  CollectNodes collector;
 
-  DepthFirst(mNode, otherDeletor);
+  DepthFirst(mNode, collector);
+
+  for(CollectNodes::iterator iter = collector.nodes.begin(); iter != collector.nodes.end(); ++iter)
+  {
+    if(*iter != mNode)
+    {
+      delete *iter;
+    }
+  }
 
   mNode->mFirstChild = NULL;
   mNode->mLastChild  = NULL;
index 24599a5..b231302 100644 (file)
@@ -215,29 +215,6 @@ struct CollectNodes
 };
 
 /*
- * Delete nodes immediately, instead of self
- */
-struct DeleteNodesWithoutSelf
-{
-  DeleteNodesWithoutSelf(TreeNode* self)
-  : mSelf(self){};
-
-  /*
-   * Call operator to delete object if given node is not self
-   */
-  void operator()(TreeNode*& n)
-  {
-    DALI_ASSERT_DEBUG(n && "Operation on NULL JSON node");
-    if(mSelf != n)
-    {
-      delete n;
-    }
-  }
-
-  const TreeNode* mSelf; ///< self node what we should not remove.
-};
-
-/*
  * Depth first walk of nodes applying given operation (unary_function)
  */
 template<typename Operation>
index 574ef08..b000325 100644 (file)
@@ -99,10 +99,10 @@ Dali::Accessibility::States CheckBoxButton::CheckBoxButtonAccessible::CalculateS
 void CheckBoxButton::OnStateChange(State newState)
 {
   // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
-  if((Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor() == Self()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+  if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
   {
     auto* accessible = GetAccessibleObject();
-    if(DALI_LIKELY(accessible))
+    if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
     {
       accessible->EmitStateChanged(Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0);
     }
index dea0ee0..70e7261 100644 (file)
@@ -207,10 +207,10 @@ Dali::Accessibility::States PushButton::PushButtonAccessible::CalculateStates()
 void PushButton::OnStateChange(State newState)
 {
   // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
-  if((Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor() == Self()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+  if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
   {
     auto* accessible = GetAccessibleObject();
-    if(DALI_LIKELY(accessible))
+    if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
     {
       accessible->EmitStateChanged(Dali::Accessibility::State::PRESSED, newState == SELECTED_STATE ? 1 : 0, 0);
 
index 9aace1a..d352f2b 100644 (file)
@@ -107,10 +107,10 @@ void RadioButton::OnStateChange(State newState)
   }
 
   // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
-  if((Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor() == Self()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+  if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
   {
     auto* accessible = GetAccessibleObject();
-    if(DALI_LIKELY(accessible))
+    if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
     {
       accessible->EmitStateChanged(Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0);
     }
index deab292..5dd9b87 100644 (file)
@@ -325,7 +325,7 @@ void ToggleButton::PrepareVisual(Property::Index index, Toolkit::Visual::Base& v
     DevelControl::UnregisterVisual(*this, index);
   }
 
-  DevelControl::RegisterVisual(*this, index, visual, enabled);
+  DevelControl::RegisterVisual(*this, index, visual, enabled, DepthIndex::CONTENT);
 }
 
 void ToggleButton::RelayoutVisual(Property::Index index, const Vector2& size)
@@ -412,10 +412,10 @@ Property::Index ToggleButton::ToggleButtonAccessible::GetDescriptionPropertyInde
 void ToggleButton::OnStateChange(State newState)
 {
   // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used
-  if((Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) && (newState == SELECTED_STATE || newState == UNSELECTED_STATE))
+  if(newState == SELECTED_STATE || newState == UNSELECTED_STATE)
   {
     auto* accessible = GetAccessibleObject();
-    if(DALI_LIKELY(accessible))
+    if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
     {
       accessible->EmitStateChanged(Dali::Accessibility::State::CHECKED, mCurrentToggleIndex ? 1 : 0, 0);
       accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION);
index e67be8e..4e99e5c 100644 (file)
@@ -798,6 +798,10 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base&
     requiredDepthIndex = depthIndex;
   }
 
+  // Change the depth index value automatically if the visual has DepthIndex to AUTO_INDEX
+  // or if RegisterVisual set DepthIndex to AUTO_INDEX.
+  const bool requiredDepthIndexChanged = (requiredDepthIndex == DepthIndex::AUTO_INDEX);
+
   // Visual replacement, existing visual should only be removed from stage when replacement ready.
   if(!mVisuals.Empty())
   {
@@ -839,11 +843,11 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base&
           mVisuals.Erase(registeredVisualsiter);
         }
 
-        // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
-        if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
-           (visual.GetDepthIndex() == 0))
+        // If the visual have a depth index as AUTO_INDEX and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
+        if(requiredDepthIndexChanged)
         {
           requiredDepthIndex = currentDepthIndex;
+          DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use replaced visual index. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
         }
       }
 
@@ -866,12 +870,10 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base&
 
   if(!visualReplaced) // New registration entry
   {
-    // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest
-    if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
-       (mVisuals.Size() > 0) &&
-       (visual.GetDepthIndex() == 0))
+    // If we have more than one visual and the visual have a depth index as AUTO_INDEX, then set it to be the highest
+    if((mVisuals.Size() > 0) && requiredDepthIndexChanged)
     {
-      int maxDepthIndex = std::numeric_limits<int>::min();
+      int maxDepthIndex = static_cast<int>(DepthIndex::CONTENT) - 1; // Start at DepthIndex::CONTENT if maxDepth index belongs to a background or no visuals have been added yet.
 
       RegisteredVisualContainer::ConstIterator       iter;
       const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
@@ -883,13 +885,20 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base&
           maxDepthIndex = visualDepthIndex;
         }
       }
-      ++maxDepthIndex;                                 // Add one to the current maximum depth index so that our added visual appears on top
-      requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background
+      requiredDepthIndex = ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top.
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use top of all visuals. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
     }
   }
 
   if(visual)
   {
+    // If required depth index still DepthIndex::AUTO_INDEX, Make it as DepthIndex::CONTENT now
+    if(requiredDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
+    {
+      requiredDepthIndex = static_cast<int>(DepthIndex::CONTENT);
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Some strange cases. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
+    }
+
     // Set determined depth index
     visual.SetDepthIndex(requiredDepthIndex);
 
@@ -1152,7 +1161,6 @@ void Control::Impl::AddTransitions(Dali::Animation&               animation,
     TransitionData::Animator* animator = (*iter);
 
     Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
-
     if(visual)
     {
 #if defined(DEBUG_ENABLED)
@@ -1198,10 +1206,10 @@ void Control::Impl::AddTransitions(Dali::Animation&               animation,
             }
 
             animation.AnimateTo(Property(child, propertyIndex),
-                                animator->targetValue,
-                                animator->alphaFunction,
-                                TimePeriod(animator->timePeriodDelay,
-                                           animator->timePeriodDuration));
+                  animator->targetValue,
+                  animator->alphaFunction,
+                  TimePeriod(animator->timePeriodDelay,
+                            animator->timePeriodDuration));
           }
         }
       }
index b2109ee..ed38e3f 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_DATA_IMPL_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.
  */
 
 // EXTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/public-api/object/property-notification.h>
 #include <dali/public-api/object/type-registry.h>
 #include <string>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
 #include <dali-toolkit/internal/builder/dictionary.h>
 #include <dali-toolkit/internal/builder/style.h>
@@ -501,12 +502,14 @@ private:
    * @param[in,out] visual The visual to register, which can be altered in this function
    * @param[in] enabled false if derived class wants to control when visual is set on stage
    * @param[in] depthIndexValueSet Set to true if the depthIndex has actually been set manually
-   * @param[in] depthIndex The visual's depth-index is set to this
+   * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+   *                       the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+   *                       Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
    *
    * @note Registering a visual with an index that already has a registered visual will replace it. The replacement will
    *       occur once the replacement visual is ready (loaded).
    */
-  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = 0);
+  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = static_cast<int>(Toolkit::DepthIndex::AUTO_INDEX));
 
   /**
    * @brief Emits the resource ready signal.
index 01b84f7..be66265 100644 (file)
@@ -151,6 +151,7 @@ void DrawableView::OnSceneConnection(int depth)
   // the designed behaviour of GlView so signal is connected regardless
   if(window)
   {
+    mPlacementWindow = window;
     DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
   }
 }
@@ -160,6 +161,13 @@ void DrawableView::OnSceneDisconnection()
   Control::OnSceneDisconnection();
 
   mNativeRenderer->Terminate();
+
+  Window window = mPlacementWindow.GetHandle();
+  if(window)
+  {
+    DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &DrawableView::OnWindowVisibilityChanged);
+    mPlacementWindow.Reset();
+  }
 }
 
 void DrawableView::AddRenderer()
index 57611cc..7a72c15 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
 #include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/object/weak-handle.h>
 #include <dali/public-api/rendering/geometry.h>
 #include <dali/public-api/rendering/shader.h>
 #include <dali/public-api/signals/render-callback.h>
@@ -142,6 +143,7 @@ private:
   bool OnRenderCallback(const RenderCallbackInput& renderCallbackInput);
 
 private:
+  WeakHandle<Window>                   mPlacementWindow;
   Dali::Toolkit::GlView::RenderingMode mRenderingMode;
 
   bool mDepth;
index 61ab62e..11fe19d 100644 (file)
@@ -176,7 +176,7 @@ void GlView::OnInitialize()
   }
 
   //Adding VisibilityChange Signal.
-  Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &GlView::OnControlVisibilityChanged);
+  self.InheritedVisibilityChangedSignal().Connect(this, &GlView::OnControlInheritedVisibilityChanged);
 }
 
 void GlView::OnSizeSet(const Vector3& targetSize)
@@ -207,21 +207,18 @@ Shader GlView::CreateShader()
   return Shader::New(SHADER_GL_VIEW_VERT, fragmentShader, Shader::Hint::NONE, "GL_VIEW");
 }
 
-void GlView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
+void GlView::OnControlInheritedVisibilityChanged(Dali::Actor actor, bool visible)
 {
   Actor self = Self();
-  if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+  if(mRenderThread)
   {
-    if(mRenderThread)
+    if(visible && DevelWindow::Get(self).IsVisible())
+    {
+      mRenderThread->Resume();
+    }
+    else
     {
-      if(visible && DevelWindow::Get(self).IsVisible())
-      {
-        mRenderThread->Resume();
-      }
-      else
-      {
-        mRenderThread->Pause();
-      }
+      mRenderThread->Pause();
     }
   }
 }
@@ -250,24 +247,19 @@ void GlView::OnSceneConnection(int depth)
 
   if(window)
   {
+    mPlacementWindow = window;
     DevelWindow::VisibilityChangedSignal(window).Connect(this, &GlView::OnWindowVisibilityChanged);
   }
-
-  if(mRenderThread)
-  {
-    if(self.GetProperty<bool>(Actor::Property::VISIBLE) && window.IsVisible())
-    {
-      mRenderThread->Resume();
-    }
-  }
 }
 
 void GlView::OnSceneDisconnection()
 {
   Control::OnSceneDisconnection();
-  if(mRenderThread)
+  Window window = mPlacementWindow.GetHandle();
+  if(window)
   {
-    mRenderThread->Pause();
+    DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &GlView::OnWindowVisibilityChanged);
+    mPlacementWindow.Reset();
   }
 }
 
index e70cd99..0d80925 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
 #include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/object/weak-handle.h>
 #include <dali/public-api/rendering/geometry.h>
 #include <dali/public-api/rendering/shader.h>
 
@@ -115,9 +116,9 @@ private:
   GlView& operator=(const GlView& GlView);
 
   /**
-   * Callback when the visibility of the GlView is changed
+   * Callback when the inherited visibility of the GlView is changed
    */
-  void OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type);
+  void OnControlInheritedVisibilityChanged(Dali::Actor actor, bool visible);
 
   /**
    * Callback when the visibility of the window is changed
@@ -147,6 +148,7 @@ private:
   Dali::NativeImageSourceQueue::ColorFormat GetColorFormat(Dali::Toolkit::GlView::ColorFormat format);
 
 private:
+  WeakHandle<Window>                   mPlacementWindow;
   std::unique_ptr<GlViewRenderThread>  mRenderThread;
   Dali::NativeImageSourceQueuePtr      mNativeImageQueue;
   Dali::Toolkit::GlView::RenderingMode mRenderingMode;
index 7f11261..200aebf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -25,6 +25,7 @@
 #include <dali/public-api/object/type-registry.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
@@ -45,13 +46,13 @@ namespace
 {
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
-constexpr float FULL_OPACITY = 1.0f;
-constexpr float LOW_OPACITY  = 0.2f;
+constexpr float FULL_OPACITY            = 1.0f;
+constexpr float LOW_OPACITY             = 0.2f;
 constexpr float TRANSITION_EFFECT_SPEED = 0.3f;
 
-constexpr int PLACEHOLDER_DEPTH_INDEX = -2;
-constexpr int PREVIOUS_VISUAL_DEPTH_INDEX  = -1;
-constexpr int CURRENT_VISUAL_DEPTH_INDEX = 0;
+constexpr int PLACEHOLDER_DEPTH_INDEX     = -2;
+constexpr int PREVIOUS_VISUAL_DEPTH_INDEX = -1;
+constexpr int CURRENT_VISUAL_DEPTH_INDEX  = 0;
 
 BaseHandle Create()
 {
@@ -64,6 +65,7 @@ DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "image", MAP, IMAGE)
 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA)
 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "placeholderImage", STRING, PLACEHOLDER_IMAGE)
 DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "enableTransitionEffect", BOOLEAN, ENABLE_TRANSITION_EFFECT)
+DALI_PROPERTY_REGISTRATION(Toolkit, ImageView, "transitionEffectOption", MAP, TRANSITION_EFFECT_OPTION)
 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA)
 DALI_TYPE_REGISTRATION_END()
 
@@ -173,7 +175,7 @@ void ImageView::SetImage(const Property::Map& map)
       visualImpl.SetCustomShader(mShaderMap);
     }
 
-    DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
+    DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT);
   }
   else
   {
@@ -210,8 +212,6 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size)
     mPreviousVisual = mVisual;
   }
 
-  
-
   // Don't bother comparing if we had a visual previously, just drop old visual and create new one
   mUrl       = url;
   mImageSize = size;
@@ -239,7 +239,7 @@ void ImageView::SetImage(const std::string& url, ImageDimensions size)
       visualImpl.SetCustomShader(mShaderMap);
     }
 
-    DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual);
+    DevelControl::RegisterVisual(*this, Toolkit::ImageView::Property::IMAGE, visual, DepthIndex::CONTENT);
   }
   else
   {
@@ -328,6 +328,11 @@ bool ImageView::IsTransitionEffectEnabled() const
   return mTransitionEffect;
 }
 
+void ImageView::SetTransitionEffectOption(const Property::Map& map)
+{
+  mTransitionEffectOptionMap = map;
+}
+
 Vector3 ImageView::GetNaturalSize()
 {
   if(mVisual)
@@ -563,7 +568,7 @@ void ImageView::ApplyFittingMode(const Vector2& size)
   bool zeroPadding = (padding == Extents());
 
   Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
-  Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+    Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
   if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
   {
     std::swap(padding.start, padding.end);
@@ -696,24 +701,50 @@ void ImageView::TransitionImageWithEffect()
       mPreviousVisual.SetDepthIndex(mPreviousVisual.GetDepthIndex() + PREVIOUS_VISUAL_DEPTH_INDEX);
     }
 
-    mTransitionAnimation = Animation::New(TRANSITION_EFFECT_SPEED);
-    mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
-    float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
-
     // Transition current image
     Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
     if(imageVisual)
     {
-      Dali::KeyFrames fadeinKeyFrames = Dali::KeyFrames::New();
-      fadeinKeyFrames.Add(0.0f, LOW_OPACITY);
-      fadeinKeyFrames.Add(1.0f, destinationAlpha);
-      mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames,  AlphaFunction::EASE_IN_OUT);
       imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX);
-    }
+      if(!mTransitionEffectOptionMap.Empty())
+      {
+        // Set user's transition effect options
+        Dali::Toolkit::TransitionData transition = Toolkit::TransitionData::New(mTransitionEffectOptionMap);
+        Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(*this);
+        mTransitionAnimation  = controlDataImpl.CreateTransition(transition);
+        if(mTransitionAnimation)
+        {
+          mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
+          mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
+          mTransitionAnimation.Play();
+        }
+        else
+        {
+          DALI_LOG_ERROR("Create Transition Animation failed");
+        }
+      }
+      else
+      {
+        mTransitionAnimation = Animation::New(TRANSITION_EFFECT_SPEED);
+        mTransitionAnimation.SetEndAction(Animation::EndAction::DISCARD);
+        float destinationAlpha = (mTransitionTargetAlpha > LOW_OPACITY) ? mTransitionTargetAlpha : LOW_OPACITY;
+
+        // Transition current image
+        Toolkit::Visual::Base imageVisual = DevelControl::GetVisual(*this, Toolkit::ImageView::Property::IMAGE);
+        if(imageVisual)
+        {
+          Dali::KeyFrames fadeinKeyFrames = Dali::KeyFrames::New();
+          fadeinKeyFrames.Add(0.0f, LOW_OPACITY);
+          fadeinKeyFrames.Add(1.0f, destinationAlpha);
+          mTransitionAnimation.AnimateBetween(DevelControl::GetVisualProperty(handle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY), fadeinKeyFrames,  AlphaFunction::EASE_IN_OUT);
+          imageVisual.SetDepthIndex(imageVisual.GetDepthIndex() + CURRENT_VISUAL_DEPTH_INDEX);
+        }
 
-    // Play transition animation
-    mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
-    mTransitionAnimation.Play();
+        // Play transition animation
+        mTransitionAnimation.FinishedSignal().Connect(this, &ImageView::OnTransitionAnimationFinishedCallback);
+        mTransitionAnimation.Play();
+      }
+    }
   }
 }
 
@@ -843,6 +874,14 @@ void ImageView::SetProperty(BaseObject* object, Property::Index index, const Pro
         }
         break;
       }
+      case Toolkit::ImageView::Property::TRANSITION_EFFECT_OPTION:
+      {
+        Property::Map map;
+        if(value.Get(map))
+        {
+          impl.SetTransitionEffectOption(map);
+        }
+      }
     }
   }
 }
index 8cf8d3a..a4cf2e7 100644 (file)
@@ -139,6 +139,11 @@ public:
   bool IsTransitionEffectEnabled() const;
 
   /**
+   * @brief Set the transition effect option.
+  */
+  void SetTransitionEffectOption(const Property::Map& map);
+
+  /**
    * @brief callback when animation for placeholder or previous visual transition effect is finished
    */
   void OnTransitionAnimationFinishedCallback(Animation& animation);
@@ -243,6 +248,7 @@ private:
   std::string     mPlaceholderUrl;                         ///< the url for the placeholder image if the image came from a PLACEHOLDER_IMAGE, empty otherwise
   Property::Map   mPropertyMap;                            ///< the Property::Map if the image came from a Property::Map, empty otherwise
   Property::Map   mShaderMap;                              ///< the Property::Map if the custom shader is set, empty otherwise
+  Property::Map   mTransitionEffectOptionMap;              ///< the Property::Map if the transition effect option is set, empty otherwise
   ImageDimensions mImageSize;                              ///< the image size
 
   Animation       mTransitionAnimation;                    ///< the animation for transition effect
index 2432fb1..29302e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -19,6 +19,7 @@
 #include <dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h>
 
 // EXTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
@@ -77,7 +78,7 @@ struct ProgressDepthIndex
   // Enum to make sure the visual order
   enum
   {
-    TRACK_VISUAL,
+    TRACK_VISUAL = Toolkit::DepthIndex::CONTENT,
     SECONDARY_PROGRESS_VISUAL,
     PROGRESS_VISUAL,
     LABEL_VISUAL,
@@ -271,13 +272,11 @@ void ProgressBar::SetProgressValue(float value)
 
     Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast(Self());
     mValueChangedSignal.Emit(self, mProgressValue, mSecondaryProgressValue);
-    if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
+
+    auto accessible = GetAccessibleObject();
+    if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
     {
-      auto accessible = GetAccessibleObject();
-      if(DALI_LIKELY(accessible))
-      {
-        accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
-      }
+      accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
     }
     RelayoutRequest();
   }
index bf177fa..fe49f3c 100644 (file)
@@ -363,13 +363,11 @@ void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source)
   if(scrollableHandle)
   {
     mScrollPositionIntervalReachedSignal.Emit(scrollableHandle.GetCurrentProperty<float>(mPropertyScrollPosition));
-    if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
+
+    auto accessible = GetAccessibleObject();
+    if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
     {
-      auto accessible = GetAccessibleObject();
-      if(DALI_LIKELY(accessible))
-      {
-        accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
-      }
+      accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
     }
   }
 }
index 5de904f..20b498c 100644 (file)
@@ -953,13 +953,11 @@ void Slider::SetValue(float value)
 {
   mValue = value;
   DisplayValue(mValue, true);
-  if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
+
+  auto accessible = GetAccessibleObject();
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
-    auto accessible = GetAccessibleObject();
-    if(DALI_LIKELY(accessible))
-    {
-      accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
-    }
+    accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
   }
 }
 
index a3dde6b..43a5884 100644 (file)
@@ -162,6 +162,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "characterSpacin
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "relativeLineSize",                     FLOAT,     RELATIVE_LINE_SIZE                  )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "verticalAlignment",                    STRING,    VERTICAL_ALIGNMENT                  )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "selectionPopupStyle",                  MAP,       SELECTION_POPUP_STYLE               )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "removeFrontInset",                     BOOLEAN,   REMOVE_FRONT_INSET                  )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "removeBackInset",                      BOOLEAN,   REMOVE_BACK_INSET                   )
 
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged",           SIGNAL_TEXT_CHANGED           )
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged",     SIGNAL_INPUT_STYLE_CHANGED    )
@@ -962,7 +964,7 @@ void TextEditor::RequestTextRelayout()
 void TextEditor::TextInserted(unsigned int position, unsigned int length, const std::string& content)
 {
   auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
     accessible->EmitTextInserted(position, length, content);
   }
@@ -971,7 +973,7 @@ void TextEditor::TextInserted(unsigned int position, unsigned int length, const
 void TextEditor::TextDeleted(unsigned int position, unsigned int length, const std::string& content)
 {
   auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
     accessible->EmitTextDeleted(position, length, content);
   }
@@ -980,7 +982,7 @@ void TextEditor::TextDeleted(unsigned int position, unsigned int length, const s
 void TextEditor::CursorPositionChanged(unsigned int oldPosition, unsigned int newPosition)
 {
   auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
     accessible->EmitTextCursorMoved(newPosition);
   }
@@ -1356,6 +1358,26 @@ void TextEditor::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type typ
   mController->ChangedLayoutDirection();
 }
 
+void TextEditor::SetRemoveFrontInset(bool remove)
+{
+  mController->SetRemoveFrontInset(remove);
+}
+
+bool TextEditor::IsRemoveFrontInset() const
+{
+  return mController->IsRemoveFrontInset();
+}
+
+void TextEditor::SetRemoveBackInset(bool remove)
+{
+  mController->SetRemoveBackInset(remove);
+}
+
+bool TextEditor::IsRemoveBackInset() const
+{
+  return mController->IsRemoveBackInset();
+}
+
 TextEditor::TextEditor(ControlBehaviour additionalBehaviour)
 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehaviour)),
   mAnimationPeriod(0.0f, 0.0f),
index 0eb9f6f..982a159 100644 (file)
@@ -440,6 +440,34 @@ public:
    */
   void AnchorClicked(const std::string& href) override;
 
+  /**
+   * @brief Set removing front inset to TextEditor.
+   *
+   * @param[in] remove Whether front inset of TextEditor has to be removed or not.
+   */
+  void SetRemoveFrontInset(const bool remove);
+
+  /**
+   * @brief Whether front inset of TextEditor is removed or not.
+   *
+   * @return True if the front inset of TextEditor is removed.
+   */
+  bool IsRemoveFrontInset() const;
+
+  /**
+   * @brief Set removing back inset to TextEditor.
+   *
+   * @param[in] remove Whether back inset of TextEditor has to be removed or not.
+   */
+  void SetRemoveBackInset(const bool remove);
+
+  /**
+   * @brief Whether back inset of TextEditor is removed or not.
+   *
+   * @return True if the back inset of TextEditor is removed.
+   */
+  bool IsRemoveBackInset() const;
+
 private: // Implementation
   /**
    * @copydoc Dali::Toolkit::Text::Controller::(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
index 067023a..984be66 100644 (file)
@@ -751,6 +751,18 @@ void TextEditor::PropertyHandler::SetProperty(Toolkit::TextEditor textEditor, Pr
       }
       break;
     }
+    case Toolkit::DevelTextEditor::Property::REMOVE_FRONT_INSET:
+    {
+      const bool remove = value.Get<bool>();
+      impl.mController->SetRemoveFrontInset(remove);
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::REMOVE_BACK_INSET:
+    {
+      const bool remove = value.Get<bool>();
+      impl.mController->SetRemoveBackInset(remove);
+      break;
+    }
   }
 }
 
@@ -1180,6 +1192,16 @@ Property::Value TextEditor::PropertyHandler::GetProperty(Toolkit::TextEditor tex
       value = map;
       break;
     }
+    case Toolkit::DevelTextEditor::Property::REMOVE_FRONT_INSET:
+    {
+      value = impl.mController->IsRemoveFrontInset();
+      break;
+    }
+    case Toolkit::DevelTextEditor::Property::REMOVE_BACK_INSET:
+    {
+      value = impl.mController->IsRemoveBackInset();
+      break;
+    }
   } //switch
   return value;
 }
index 4d68826..8336b14 100644 (file)
@@ -147,6 +147,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "strikethrough",
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "inputStrikethrough",               MAP,       INPUT_STRIKETHROUGH                 )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "characterSpacing",                 FLOAT,     CHARACTER_SPACING                   )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "selectionPopupStyle",              MAP,       SELECTION_POPUP_STYLE               )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "removeFrontInset",                 BOOLEAN,   REMOVE_FRONT_INSET                  )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "removeBackInset",                  BOOLEAN,   REMOVE_BACK_INSET                   )
 
 DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "textChanged",           SIGNAL_TEXT_CHANGED           )
 DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "maxLengthReached",      SIGNAL_MAX_LENGTH_REACHED     )
@@ -888,7 +890,7 @@ void TextField::SetEditable(bool editable)
 void TextField::TextInserted(unsigned int position, unsigned int length, const std::string& content)
 {
   auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
     accessible->EmitTextInserted(position, length, content);
   }
@@ -897,7 +899,7 @@ void TextField::TextInserted(unsigned int position, unsigned int length, const s
 void TextField::TextDeleted(unsigned int position, unsigned int length, const std::string& content)
 {
   auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
     accessible->EmitTextDeleted(position, length, content);
   }
@@ -906,7 +908,7 @@ void TextField::TextDeleted(unsigned int position, unsigned int length, const st
 void TextField::CursorPositionChanged(unsigned int oldPosition, unsigned int newPosition)
 {
   auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
+  if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
   {
     accessible->EmitTextCursorMoved(newPosition);
   }
@@ -1204,6 +1206,26 @@ void TextField::SetSpannedText(const Text::Spanned& spannedText)
   mController->SetSpannedText(spannedText);
 }
 
+void TextField::SetRemoveFrontInset(bool remove)
+{
+  mController->SetRemoveFrontInset(remove);
+}
+
+bool TextField::IsRemoveFrontInset() const
+{
+  return mController->IsRemoveFrontInset();
+}
+
+void TextField::SetRemoveBackInset(bool remove)
+{
+  mController->SetRemoveBackInset(remove);
+}
+
+bool TextField::IsRemoveBackInset() const
+{
+  return mController->IsRemoveBackInset();
+}
+
 std::string TextField::TextFieldAccessible::GetName() const
 {
   if(IsHiddenInput())
index 215fd10..ed1a008 100644 (file)
@@ -412,6 +412,34 @@ public:
    */
   void SetSpannedText(const Text::Spanned& spannedText);
 
+  /**
+   * @brief Set removing front inset to TextField.
+   *
+   * @param[in] remove Whether front inset of TextField has to be removed or not.
+   */
+  void SetRemoveFrontInset(const bool remove);
+
+  /**
+   * @brief Whether front inset of TextField is removed or not.
+   *
+   * @return True if the front inset of TextField is removed.
+   */
+  bool IsRemoveFrontInset() const;
+
+  /**
+   * @brief Set removing back inset to TextField.
+   *
+   * @param[in] remove Whether back inset of TextField has to be removed or not.
+   */
+  void SetRemoveBackInset(const bool remove);
+
+  /**
+   * @brief Whether back inset of TextField is removed or not.
+   *
+   * @return True if the back inset of TextField is removed.
+   */
+  bool IsRemoveBackInset() const;
+
 private: // Implementation
   /**
    * @copydoc Dali::Toolkit::Text::Controller::(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
index 45af9b7..5151ef1 100644 (file)
@@ -709,6 +709,18 @@ void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Prope
       }
       break;
     }
+    case Toolkit::DevelTextField::Property::REMOVE_FRONT_INSET:
+    {
+      const bool remove = value.Get<bool>();
+      impl.mController->SetRemoveFrontInset(remove);
+      break;
+    }
+    case Toolkit::DevelTextField::Property::REMOVE_BACK_INSET:
+    {
+      const bool remove = value.Get<bool>();
+      impl.mController->SetRemoveBackInset(remove);
+      break;
+    }
   }
 }
 
@@ -1096,6 +1108,17 @@ Property::Value TextField::PropertyHandler::GetProperty(Toolkit::TextField textF
       value = map;
       break;
     }
+    case Toolkit::DevelTextField::Property::REMOVE_FRONT_INSET:
+    {
+      value = impl.mController->IsRemoveFrontInset();
+      break;
+    }
+    case Toolkit::DevelTextField::Property::REMOVE_BACK_INSET:
+    {
+      value = impl.mController->IsRemoveBackInset();
+      break;
+    }
+
   } //switch
   return value;
 }
index 5309e89..5af0fe1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 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.
@@ -46,6 +46,7 @@
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
 #include <dali-toolkit/public-api/visuals/visual-properties.h>
 
@@ -71,7 +72,7 @@ const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT
  * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
  */
 const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] =
-{
+  {
     0.0f, // VerticalAlignment::TOP
     0.5f, // VerticalAlignment::CENTER
     1.0f  // VerticalAlignment::BOTTOM
@@ -89,7 +90,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT
 #endif
 
 const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
-{
+  {
     {"IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE},
     {"FINISH_LOOP", Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP},
 };
@@ -146,6 +147,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "anchorColor",
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "anchorClickedColor",           VECTOR4, ANCHOR_CLICKED_COLOR           )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "removeFrontInset",             BOOLEAN, REMOVE_FRONT_INSET             )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "removeBackInset",              BOOLEAN, REMOVE_BACK_INSET              )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "cutout",                       BOOLEAN, CUTOUT                         )
 
 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, TextLabel, "textColor",      Color::BLACK,     TEXT_COLOR   )
 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit,    TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR, 0)
@@ -604,6 +606,19 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro
         impl.mController->SetRemoveBackInset(remove);
         break;
       }
+      case Toolkit::DevelTextLabel::Property::CUTOUT:
+      {
+        const bool cutout = value.Get<bool>();
+
+        impl.mController->SetTextCutout(cutout);
+
+        // Property doesn't affect the layout, only Visual must be updated
+        TextVisual::EnableRendererUpdate(impl.mVisual);
+
+        // No need to trigger full re-layout. Instead call UpdateRenderer() directly
+        TextVisual::UpdateRenderer(impl.mVisual);
+        break;
+      }
     }
 
     // Request relayout when text update is needed. It's necessary to call it
@@ -888,6 +903,11 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index
         value = impl.mController->IsRemoveBackInset();
         break;
       }
+      case Toolkit::DevelTextLabel::Property::CUTOUT:
+      {
+        value = impl.mController->IsTextCutout();
+        break;
+      }
     }
   }
 
@@ -944,7 +964,7 @@ void TextLabel::OnInitialize()
   propertyMap.Add(Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT);
 
   mVisual = Toolkit::VisualFactory::Get().CreateVisual(propertyMap);
-  DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual);
+  DevelControl::RegisterVisual(*this, Toolkit::TextLabel::Property::TEXT, mVisual, DepthIndex::CONTENT);
 
   TextVisual::SetAnimatableTextColorProperty(mVisual, Toolkit::TextLabel::Property::TEXT_COLOR);
 
@@ -1080,6 +1100,49 @@ void TextLabel::OnPropertySet(Property::Index index, const Property::Value& prop
       CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
       break;
     }
+    case Toolkit::Control::Property::BACKGROUND:
+    {
+      const Vector4 backgroundColor = propertyValue.Get<Vector4>();
+
+      if(mController->IsTextCutout())
+      {
+        DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false);
+        mController->SetBackgroundWithCutoutEnabled(true);
+        mController->SetBackgroundColorWithCutout(backgroundColor);
+      }
+
+      break;
+    }
+    case Toolkit::DevelTextLabel::Property::CUTOUT:
+    {
+      const bool cutoutEnabled = propertyValue.Get<bool>();
+
+      if(cutoutEnabled)
+      {
+        Vector4 backgroundColor = Vector4::ZERO;
+
+        const Property::Map backgroundMap   = Self().GetProperty(Toolkit::Control::Property::BACKGROUND).Get<Property::Map>();
+        Property::Value*    backgroundValue = backgroundMap.Find(ColorVisual::Property::MIX_COLOR);
+        if(backgroundValue)
+        {
+          backgroundColor = backgroundValue->Get<Vector4>();
+        }
+
+        DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false);
+        mController->SetBackgroundWithCutoutEnabled(true);
+        mController->SetBackgroundColorWithCutout(backgroundColor);
+      }
+      else
+      {
+        DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, true);
+
+        Property::Map backgroundMapSet;
+        mController->SetBackgroundWithCutoutEnabled(false);
+      }
+
+      TextVisual::SetRequireRender(mVisual, cutoutEnabled);
+      break;
+    }
     default:
     {
       Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
@@ -1106,10 +1169,13 @@ void TextLabel::OnSceneDisconnection()
       mLastAutoScrollEnabled = false;
     }
 
-    const Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = mTextScroller->GetStopMode();
-    mTextScroller->SetStopMode(Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE);
-    mTextScroller->StopScrolling();
-    mTextScroller->SetStopMode(stopMode);
+    if(mTextScroller->IsScrolling())
+    {
+      const Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = mTextScroller->GetStopMode();
+      mTextScroller->SetStopMode(Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE);
+      mTextScroller->StopScrolling();
+      mTextScroller->SetStopMode(stopMode);
+    }
   }
   Control::OnSceneDisconnection();
 }
@@ -1118,6 +1184,12 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container)
 {
   DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::OnRelayout\n");
 
+  if(mTextScroller && mTextScroller->IsStop())
+  {
+    // When auto scroll is playing, it triggers a relayout only when an update is absolutely necessary.
+    return;
+  }
+
   Actor self = Self();
 
   Extents padding;
@@ -1286,12 +1358,8 @@ void TextLabel::ScrollingFinished()
 {
   // Pure Virtual from TextScroller Interface
   DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n");
-
-  if(mController->IsAutoScrollEnabled() || !mController->IsMultiLineEnabled())
-  {
-    mController->SetAutoScrollEnabled(false);
-    RequestTextRelayout();
-  }
+  mController->SetAutoScrollEnabled(false);
+  RequestTextRelayout();
 }
 
 void TextLabel::OnLayoutDirectionChanged(Actor actor, LayoutDirection::Type type)
index c121cc7..9edac2d 100644 (file)
@@ -41,6 +41,7 @@
 #include <dali/public-api/object/type-registry.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/controls/web-view/web-back-forward-list.h>
 #include <dali-toolkit/devel-api/controls/web-view/web-settings.h>
@@ -867,7 +868,7 @@ void WebView::OnFrameRendered()
 
     if(mVisual)
     {
-      DevelControl::RegisterVisual(*this, Toolkit::WebView::Property::URL, mVisual);
+      DevelControl::RegisterVisual(*this, Toolkit::WebView::Property::URL, mVisual, DepthIndex::CONTENT);
       EnableBlendMode(!mVideoHoleEnabled);
     }
   }
index 388f0c2..0d2d621 100644 (file)
@@ -1,4 +1,4 @@
-attribute mediump vec2    aPosition;
+attribute   highp vec2    aPosition;
 attribute mediump vec2    aTexCoord;
 attribute mediump vec4    aColor;
 uniform   mediump vec2    uOffset;
@@ -8,7 +8,7 @@ varying   mediump vec4    vColor;
 
 void main()
 {
-  mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
+  highp vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
   gl_Position = uMvpMatrix * position;
   vTexCoord = aTexCoord;
   vColor = aColor;
index 8044923..99cc227 100644 (file)
@@ -768,13 +768,13 @@ bool Controller::EventHandler::DeleteEvent(Controller& controller, int keyCode)
   else if((controller.mImpl->mEventData->mPrimaryCursorPosition > 0) && (keyCode == Dali::DALI_KEY_BACKSPACE))
   {
     // Remove the character before the current cursor position
-    removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE);
+    removed = TextUpdater::RemoveText(controller, -1, 1, UPDATE_INPUT_STYLE, false);
   }
   else if((controller.mImpl->mEventData->mPrimaryCursorPosition < controller.mImpl->mModel->mLogicalModel->mText.Count()) &&
           (keyCode == Dali::DevelKey::DALI_KEY_DELETE))
   {
     // Remove the character after the current cursor position
-    removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE);
+    removed = TextUpdater::RemoveText(controller, 0, 1, UPDATE_INPUT_STYLE, false);
   }
 
   if(removed)
@@ -825,7 +825,8 @@ InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextE
       const bool textDeleted = TextUpdater::RemoveText(controller,
                                                        inputMethodContextEvent.cursorOffset,
                                                        inputMethodContextEvent.numberOfChars,
-                                                       DONT_UPDATE_INPUT_STYLE);
+                                                       DONT_UPDATE_INPUT_STYLE,
+                                                       false);
 
       if(textDeleted)
       {
index f70d8af..10a76f1 100644 (file)
@@ -53,6 +53,7 @@ constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
 
 const char* EMPTY_STRING         = "";
 const char* MIME_TYPE_TEXT_PLAIN = "text/plain;charset=utf-8";
+const char* MIME_TYPE_HTML       = "application/xhtml+xml";
 
 } // namespace
 
@@ -1161,6 +1162,12 @@ bool Controller::Impl::CopyStringToClipboard(const std::string& source)
   return false;
 }
 
+bool Controller::Impl::IsClipboardEmpty()
+{
+  bool result(Clipboard::IsAvailable() && EnsureClipboardCreated() && (mClipboard.HasType(MIME_TYPE_TEXT_PLAIN) || mClipboard.HasType(MIME_TYPE_HTML)));
+  return !result;
+}
+
 void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
 {
   std::string selectedText;
index 56ca85b..0b404cc 100644 (file)
@@ -374,7 +374,8 @@ struct Controller::Impl
     mTextFitArrayEnabled(false),
     mIsLayoutDirectionChanged(false),
     mIsUserInteractionEnabled(true),
-    mProcessorRegistered(false)
+    mProcessorRegistered(false),
+    mTextCutout(false)
   {
     mModel = Model::New();
 
@@ -616,12 +617,6 @@ struct Controller::Impl
     return mClipboard != nullptr ? true : false;
   }
 
-  bool IsClipboardEmpty()
-  {
-    bool result(Clipboard::IsAvailable() && EnsureClipboardCreated() && mClipboard.NumberOfItems());
-    return !result; // If NumberOfItems greater than 0, return false
-  }
-
   bool IsClipboardVisible()
   {
     bool result(Clipboard::IsAvailable() && EnsureClipboardCreated() && mClipboard.IsVisible());
@@ -629,6 +624,14 @@ struct Controller::Impl
   }
 
   /**
+   * @brief Whether the clipboard is empty or not.
+   * Checks the types that the text controller can paste and returns the result.
+   *
+   * @return Return whether or not the clipboard is empty.
+   */
+  bool IsClipboardEmpty();
+
+  /**
    * @copydoc Controller::GetLayoutDirection()
    */
   Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
@@ -1106,6 +1109,7 @@ public:
   bool  mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
   bool  mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled.
   bool  mProcessorRegistered : 1;      ///< Whether the text controller registered into processor or not.
+  bool  mTextCutout : 1;               ///< Whether the text cutout enabled.
 
 private:
   friend ControllerImplEventHandler;
index 2ceee77..59da80a 100644 (file)
@@ -208,7 +208,8 @@ void Controller::TextUpdater::InsertText(Controller& controller, const std::stri
     removedPrevious = RemoveText(controller,
                                  -static_cast<int>(eventData->mPrimaryCursorPosition - eventData->mPreEditStartPosition),
                                  eventData->mPreEditLength,
-                                 DONT_UPDATE_INPUT_STYLE);
+                                 DONT_UPDATE_INPUT_STYLE,
+                                 true);
 
     eventData->mPrimaryCursorPosition = eventData->mPreEditStartPosition;
     eventData->mPreEditLength         = 0u;
@@ -495,7 +496,8 @@ bool Controller::TextUpdater::RemoveText(
   Controller&          controller,
   int                  cursorOffset,
   int                  numberOfCharacters,
-  UpdateInputStyleType type)
+  UpdateInputStyleType type,
+  bool                 isDeletingPreEdit)
 {
   bool removed   = false;
   bool removeAll = false;
@@ -608,7 +610,10 @@ bool Controller::TextUpdater::RemoveText(
       if(removeAll)
       {
         impl.ClearPreEditFlag();
-        textUpdateInfo.mNumberOfCharactersToAdd = 0;
+        if(!isDeletingPreEdit)
+        {
+          textUpdateInfo.mNumberOfCharactersToAdd = 0;
+        }
       }
 
       // Updates the text style runs by removing characters. Runs with no characters are removed.
index 47403f6..319697f 100644 (file)
@@ -63,9 +63,10 @@ struct Controller::TextUpdater
    * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
    * @param[in] numberOfCharacters The number of characters to delete from the cursorOffset.
    * @param[in] type Whether to update the input style.
+   * @param[in] isDeletingPreEdit Whether to remove pre-edit when inserting text.
    * @return True if the remove was successful.
    */
-  static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type);
+  static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type, bool isDeletingPreEdit);
 
   /**
    * @brief Checks if text is selected and if so removes it.
index d17e187..da697ba 100644 (file)
@@ -48,6 +48,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT
 
 const char* EMPTY_STRING         = "";
 const char* MIME_TYPE_TEXT_PLAIN = "text/plain;charset=utf-8";
+const char* MIME_TYPE_HTML       = "application/xhtml+xml";
 
 template<typename Type>
 void EnsureCreated(Type*& object)
@@ -324,6 +325,21 @@ void Controller::SetRemoveBackInset(bool remove)
   mImpl->mModel->mRemoveBackInset = remove;
 }
 
+bool Controller::IsTextCutout() const
+{
+  return mImpl->mTextCutout;
+}
+
+void Controller::SetTextCutout(bool cutout)
+{
+  if(cutout != mImpl->mTextCutout)
+  {
+    mImpl->mModel->mVisualModel->SetCutoutEnabled(cutout);
+    mImpl->mTextCutout = cutout;
+    mImpl->RequestRelayout();
+  }
+}
+
 void Controller::ChangedLayoutDirection()
 {
   mImpl->mIsLayoutDirectionChanged = true;
@@ -994,6 +1010,17 @@ float Controller::GetDashedUnderlineGap() const
   return mImpl->mModel->mVisualModel->GetDashedUnderlineGap();
 }
 
+void Controller::SetOutlineOffset(const Vector2& outlineOffset)
+{
+  mImpl->mModel->mVisualModel->SetOutlineOffset(outlineOffset);
+  mImpl->RequestRelayout();
+}
+
+const Vector2& Controller::GetOutlineOffset() const
+{
+  return mImpl->mModel->mVisualModel->GetOutlineOffset();
+}
+
 void Controller::SetOutlineColor(const Vector4& color)
 {
   mImpl->mModel->mVisualModel->SetOutlineColor(color);
@@ -1016,6 +1043,20 @@ uint16_t Controller::GetOutlineWidth() const
   return mImpl->mModel->mVisualModel->GetOutlineWidth();
 }
 
+void Controller::SetOutlineBlurRadius(const float& outlineBlurRadius)
+{
+  if(fabsf(GetOutlineBlurRadius() - outlineBlurRadius) > Math::MACHINE_EPSILON_1)
+  {
+    mImpl->mModel->mVisualModel->SetOutlineBlurRadius(outlineBlurRadius);
+    mImpl->RequestRelayout();
+  }
+}
+
+const float& Controller::GetOutlineBlurRadius() const
+{
+  return mImpl->mModel->mVisualModel->GetOutlineBlurRadius();
+}
+
 void Controller::SetBackgroundColor(const Vector4& color)
 {
   mImpl->mModel->mVisualModel->SetBackgroundColor(color);
@@ -1505,6 +1546,28 @@ void Controller::SetVisualTransformOffset(Vector2 offset)
   mImpl->mModel->mVisualTransformOffset = offset;
 }
 
+void Controller::SetBackgroundWithCutoutEnabled(bool cutout)
+{
+  mImpl->mModel->mVisualModel->SetBackgroundWithCutoutEnabled(cutout);
+  RequestRelayout();
+}
+
+bool Controller::IsBackgroundWithCutoutEnabled() const
+{
+  return mImpl->mModel->mVisualModel->IsBackgroundWithCutoutEnabled();
+}
+
+void Controller::SetBackgroundColorWithCutout(const Vector4& color)
+{
+  mImpl->mModel->mVisualModel->SetBackgroundColorWithCutout(color);
+  mImpl->RequestRelayout();
+}
+
+const Vector4 Controller::GetBackgroundColorWithCutout() const
+{
+  return mImpl->mModel->mVisualModel->GetBackgroundColorWithCutout();
+}
+
 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
 {
   return Relayouter::Relayout(*this, size, layoutDirection);
@@ -1728,11 +1791,27 @@ void Controller::PasteClipboardItemEvent(uint32_t id, const char* mimeType, cons
   mImpl->mClipboard.DataReceivedSignal().Disconnect(this, &Controller::PasteClipboardItemEvent);
 
   // If the id is 0u, it is an invalid response.
+  if(id == 0u)
+  {
+    return;
+  }
+
   // text-controller allows only plain text type.
-  if(id != 0u && !strncmp(mimeType, MIME_TYPE_TEXT_PLAIN, strlen(MIME_TYPE_TEXT_PLAIN)))
+  if(!strncmp(mimeType, MIME_TYPE_TEXT_PLAIN, strlen(MIME_TYPE_TEXT_PLAIN)))
   {
     EventHandler::PasteClipboardItemEvent(*this, data);
   }
+  else if(!strncmp(mimeType, MIME_TYPE_HTML, strlen(MIME_TYPE_HTML)))
+  {
+    // This does not mean that text controls can parse html.
+    // This is temporary code, as text controls do not support html type data.
+    // Simply remove the tags inside the angle brackets.
+    // Once multiple types and data can be stored in the clipboard, this code should be removed.
+    std::regex reg("<[^>]*>");
+    std::string result = regex_replace(data, reg, "");
+
+    EventHandler::PasteClipboardItemEvent(*this, result.c_str());
+  }
 }
 
 void Controller::PasteText()
@@ -1742,8 +1821,11 @@ void Controller::PasteText()
     // Connect the signal before calling GetData() of the clipboard.
     mImpl->mClipboard.DataReceivedSignal().Connect(this, &Controller::PasteClipboardItemEvent);
 
+    // If there is no plain text type data on the clipboard, request html type data.
+    std::string mimeType = mImpl->mClipboard.HasType(MIME_TYPE_TEXT_PLAIN) ? MIME_TYPE_TEXT_PLAIN : MIME_TYPE_HTML;
+
     // Request clipboard service to retrieve an item.
-    uint id = mImpl->mClipboard.GetData(MIME_TYPE_TEXT_PLAIN);
+    uint id = mImpl->mClipboard.GetData(mimeType);
     if(id == 0u)
     {
       // If the return id is 0u, the signal is not emitted, we must disconnect signal here.
index b8ff325..20ad0f0 100644 (file)
@@ -1280,6 +1280,20 @@ public: // Default style & Input style
   float GetDashedUnderlineGap() const;
 
   /**
+   * @brief Set the outline offset.
+   *
+   * @param[in] outlineOffset The outline offset.
+   */
+  void SetOutlineOffset(const Vector2& outlineOffset);
+
+  /**
+   * @brief Retrieve the outline offset.
+   *
+   * @return The outline offset.
+   */
+  const Vector2& GetOutlineOffset() const;
+
+  /**
    * @brief Set the outline color.
    *
    * @param[in] color color of outline.
@@ -1308,6 +1322,20 @@ public: // Default style & Input style
   uint16_t GetOutlineWidth() const;
 
   /**
+   * @brief Set the outline blur radius.
+   *
+   * @param[in] outlineBlurRadius The outline blur radius, 0,0 indicates no blur.
+   */
+  void SetOutlineBlurRadius(const float& outlineBlurRadius);
+
+  /**
+   * @brief Retrieve the outline blur radius.
+   *
+   * @return The outline blur radius.
+   */
+  const float& GetOutlineBlurRadius() const;
+
+  /**
    * @brief Set the background color.
    *
    * @param[in] color color of background.
@@ -1648,6 +1676,34 @@ public: // Default style & Input style
    */
   void SetVisualTransformOffset(Vector2 offset);
 
+  /**
+   * @brief Sets whether background color with cutout is enabled.
+   *
+   * @param[in] enable True if enabled.
+   */
+  void SetBackgroundWithCutoutEnabled(bool enable);
+
+  /**
+   * @brief Whether background color with cutout is enabled.
+   *
+   * @return True if enabled.
+   */
+  bool IsBackgroundWithCutoutEnabled() const;
+
+  /**
+   * @brief Sets whether background color with cutout.
+   *
+   * @param[in] color The color to set.
+   */
+  void SetBackgroundColorWithCutout(const Vector4& color);
+
+  /**
+   * @brief Retrieves background color with cutout.
+   *
+   * @return The color.
+   */
+  const Vector4 GetBackgroundColorWithCutout() const;
+
 public: // Queries & retrieves.
   /**
    * @brief Return the layout engine.
@@ -1824,6 +1880,18 @@ public: // Queries & retrieves.
   void SetRemoveBackInset(bool remove);
 
   /**
+   * @brief Retrieves cutout value to model
+   * @return The value of cutout for the text
+   */
+  bool IsTextCutout() const;
+
+  /**
+   * @brief Sets cutout value to model
+   * @param[in] cutout The value of cutout for the text
+   */
+  void SetTextCutout(bool cutout);
+
+  /**
    * @brief Sets SetMatchLayoutDirection value to model
    * @param[in] match The value of matchLayoutDirection for the text
    */
index 5328af1..21d9f31 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_GLYPH_RUN_H
 
 /*
- * Copyright (c) 2021 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.
@@ -32,8 +32,8 @@ namespace Text
  */
 struct GlyphRun
 {
-  GlyphIndex glyphIndex;     ///< Index to the first glyph.
-  Length     numberOfGlyphs; ///< Number of glyphs in the run.
+  GlyphIndex glyphIndex{0u};     ///< Index to the first glyph.
+  Length     numberOfGlyphs{0u}; ///< Number of glyphs in the run.
 };
 
 } // namespace Text
index 5d5b28b..12f3820 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_LINE_RUN_H
 
 /*
- * Copyright (c) 2022 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.
@@ -33,19 +33,19 @@ namespace Text
  */
 struct LineRun
 {
-  GlyphRun           glyphRun;                      ///< The initial glyph index and the number of glyphs of the run.
-  CharacterRun       characterRun;                  ///< The initial character index and the number of characters of the run.
-  float              width;                         ///< The line's width.
-  float              ascender;                      ///< The line's ascender.
-  float              descender;                     ///< The line's descender.
-  float              extraLength;                   ///< The length of the white spaces at the end of the line.
-  float              alignmentOffset;               ///< The horizontal alignment offset.
-  float              lineSpacing;                   ///< The line's spacing
-  CharacterDirection direction : 1;                 ///< Direction of the first character of the paragraph.
-  bool               ellipsis : 1;                  ///< Wheter ellipsis is added to the line.
-  bool               isSplitToTwoHalves;            ///< Whether the second half is defined. When split line to two halves to set Ellipsis in the MIDDLE of line. The second half is the second part of line after Ellipsis.
-  GlyphRun           glyphRunSecondHalf;            ///< The initial glyph index and the number of glyphs of the run for the second half of line.
-  CharacterRun       characterRunForSecondHalfLine; ///< The initial character index and the number of characters of the run for the second half of line.
+  GlyphRun           glyphRun{};                      ///< The initial glyph index and the number of glyphs of the run.
+  CharacterRun       characterRun{};                  ///< The initial character index and the number of characters of the run.
+  float              width;                           ///< The line's width.
+  float              ascender;                        ///< The line's ascender.
+  float              descender;                       ///< The line's descender.
+  float              extraLength;                     ///< The length of the white spaces at the end of the line.
+  float              alignmentOffset;                 ///< The horizontal alignment offset.
+  float              lineSpacing;                     ///< The line's spacing
+  CharacterDirection direction : 1;                   ///< Direction of the first character of the paragraph.
+  bool               ellipsis : 1;                    ///< Wheter ellipsis is added to the line.
+  bool               isSplitToTwoHalves;              ///< Whether the second half is defined. When split line to two halves to set Ellipsis in the MIDDLE of line. The second half is the second part of line after Ellipsis.
+  GlyphRun           glyphRunSecondHalf{};            ///< The initial glyph index and the number of glyphs of the run for the second half of line.
+  CharacterRun       characterRunForSecondHalfLine{}; ///< The initial character index and the number of characters of the run for the second half of line.
 };
 
 /**
index 5ccaad0..787bcfa 100644 (file)
@@ -450,6 +450,7 @@ struct AtlasRenderer::Impl
     const bool       underlineEnabled = view.IsUnderlineEnabled();
     const uint16_t   outlineWidth     = view.GetOutlineWidth();
     const Vector4&   outlineColor(view.GetOutlineColor());
+    const Vector2&   outlineOffset(view.GetOutlineOffset());
     const bool       isOutline            = 0u != outlineWidth;
     const GlyphInfo* hyphens              = view.GetHyphens();
     const Length*    hyphenIndices        = view.GetHyphenIndices();
@@ -656,7 +657,7 @@ struct AtlasRenderer::Impl
 
         if(0u != slot.mImageId) // invalid slot id, glyph has failed to be added to atlas
         {
-          Vector2 positionPlusOutlineOffset = position;
+          Vector2 positionPlusOutlineOffset = position + outlineOffset;
           if(isOutline)
           {
             // Add an offset to the text.
index 1c31199..6ca9d17 100644 (file)
@@ -19,7 +19,9 @@
 #include <dali-toolkit/internal/text/rendering/text-typesetter.h>
 
 // EXTERNAL INCLUDES
+#include <cmath>
 #include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/debug.h>
 #include <dali/integration-api/trace.h>
 #include <dali/public-api/common/constants.h>
 #include <dali/public-api/math/math-utils.h>
@@ -584,6 +586,8 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
   const Vector2* const    positionBuffer               = model->GetLayout();
   const Vector4* const    backgroundColorsBuffer       = model->GetBackgroundColors();
   const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices();
+  const bool              removeFrontInset             = model->IsRemoveFrontInset();
+  const bool              removeBackInset              = model->IsRemoveBackInset();
 
   const DevelText::VerticalLineAlignment::Type verLineAlign = model->GetVerticalLineAlignment();
 
@@ -653,14 +657,36 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
       }
 
       // Calculate the positions of leftmost and rightmost glyphs in the current line
-      if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+      if(removeFrontInset)
       {
-        left = position->x - glyphInfo->xBearing;
+        if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+        {
+          left = position->x;
+        }
+      }
+      else
+      {
+        const float originPositionLeft = position->x - glyphInfo->xBearing;
+        if((originPositionLeft < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+        {
+          left = originPositionLeft;
+        }
       }
 
-      if(position->x + glyphInfo->width > right)
+      if(removeBackInset)
       {
-        right = position->x - glyphInfo->xBearing + glyphInfo->advance;
+        if(position->x + glyphInfo->width > right)
+        {
+          right = position->x - position->x + glyphInfo->width;
+        }
+      }
+      else
+      {
+        const float originPositionRight = position->x - glyphInfo->xBearing + glyphInfo->advance;
+        if(originPositionRight > right)
+        {
+          right = originPositionRight;
+        }
       }
 
       prevBackgroundColorIndex = backgroundColorIndex;
@@ -896,6 +922,24 @@ ViewModel* Typesetter::GetViewModel()
 
 PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
 {
+  Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
+  PixelData pixelData = Devel::PixelBuffer::Convert(result);
+
+  return pixelData;
+}
+
+PixelData Typesetter::RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer mask, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, float originAlpha)
+{
+  Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat);
+  SetMaskForImageBuffer(mask, result, size.width, size.height, originAlpha);
+
+  PixelData pixelData = Devel::PixelBuffer::Convert(result);
+
+  return pixelData;
+}
+
+Devel::PixelBuffer Typesetter::RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat)
+{
   DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_RENDERING_TYPESETTER");
   // @todo. This initial implementation for a TextLabel has only one visible page.
 
@@ -904,12 +948,10 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
 
   // Retrieves the layout size.
   const Size& layoutSize = mModel->GetLayoutSize();
-
   const int32_t outlineWidth = static_cast<int32_t>(mModel->GetOutlineWidth());
 
   // Set the offset for the horizontal alignment according to the text direction and outline width.
   int32_t penX = 0;
-
   switch(mModel->GetHorizontalAlignment())
   {
     case HorizontalAlignment::BEGIN:
@@ -931,7 +973,6 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
 
   // Set the offset for the vertical alignment.
   int32_t penY = 0u;
-
   switch(mModel->GetVerticalAlignment())
   {
     case VerticalAlignment::TOP:
@@ -941,8 +982,9 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     }
     case VerticalAlignment::CENTER:
     {
-      penY = static_cast<int32_t>(0.5f * (size.height - layoutSize.height));
+      penY = static_cast<int32_t>(std::round(0.5f * (size.height - layoutSize.height)));
       penY = penY < 0.f ? 0.f : penY;
+
       break;
     }
     case VerticalAlignment::BOTTOM:
@@ -996,6 +1038,13 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
       // Create the image buffer for outline
       Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
 
+      const float& blurRadius = mModel->GetOutlineBlurRadius();
+
+      if(blurRadius > Math::MACHINE_EPSILON_1)
+      {
+        outlineImageBuffer.ApplyGaussianBlur(blurRadius);
+      }
+
       // Combine the two buffers
       CombineImageBuffer(imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight, true);
     }
@@ -1047,6 +1096,18 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
       CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
     }
 
+    // Generate the background_with_mask if enabled
+    const bool backgroundWithCutoutEnabled   = mModel->IsBackgroundWithCutoutEnabled();
+    if((backgroundWithCutoutEnabled) && RENDER_OVERLAY_STYLE != behaviour)
+    {
+      Devel::PixelBuffer backgroundImageBuffer;
+
+      backgroundImageBuffer = CreateFullBackgroundBuffer(bufferWidth, bufferHeight, mModel->GetBackgroundColorWithCutout());
+
+      // Combine the two buffers
+      CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true);
+    }
+
     if(RENDER_OVERLAY_STYLE == behaviour)
     {
       if(mModel->IsUnderlineEnabled())
@@ -1083,10 +1144,30 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     }
   }
 
-  // Create the final PixelData for the combined image buffer
-  PixelData pixelData = Devel::PixelBuffer::Convert(imageBuffer);
+  return imageBuffer;
+}
+
+Devel::PixelBuffer Typesetter::CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor)
+{
+  const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
+  uint8_t backgroundColorAlpha = static_cast<uint8_t>(backgroundColor.a * 255.f);
+
+  Devel::PixelBuffer buffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
 
-  return pixelData;
+  uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(buffer.GetBuffer());
+
+  uint32_t packedBackgroundColor       = 0u;
+  uint8_t* packedBackgroundColorBuffer = reinterpret_cast<uint8_t*>(&packedBackgroundColor);
+
+  // Write the color to the pixel buffer
+  *(packedBackgroundColorBuffer + 3u) = backgroundColorAlpha;
+  *(packedBackgroundColorBuffer + 2u) = static_cast<uint8_t>(backgroundColor.b * backgroundColorAlpha);
+  *(packedBackgroundColorBuffer + 1u) = static_cast<uint8_t>(backgroundColor.g * backgroundColorAlpha);
+  *(packedBackgroundColorBuffer)      = static_cast<uint8_t>(backgroundColor.r * backgroundColorAlpha);
+
+  std::fill(bitmapBuffer, bitmapBuffer + bufferSizeInt, packedBackgroundColor);
+
+  return buffer;
 }
 
 Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Typesetter::Style style, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset, const GlyphIndex fromGlyphIndex, const GlyphIndex toGlyphIndex)
@@ -1101,6 +1182,9 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con
   const GlyphInfo* __restrict__ hyphens                 = mModel->GetHyphens();
   const Length* __restrict__ hyphenIndices              = mModel->GetHyphenIndices();
   const Length hyphensCount                             = mModel->GetHyphensCount();
+  const bool removeFrontInset                           = mModel->IsRemoveFrontInset();
+  const bool removeBackInset                            = mModel->IsRemoveBackInset();
+  const bool cutoutEnabled                              = mModel->IsCutoutEnabled();
 
   // Elided text info. Indices according to elided text and Ellipsis position.
   const auto startIndexOfGlyphs              = mModel->GetStartIndexOfElidedGlyphs();
@@ -1149,11 +1233,15 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con
 
     if(style == Typesetter::STYLE_OUTLINE)
     {
+      const Vector2& outlineOffset = mModel->GetOutlineOffset();
+
       glyphData.horizontalOffset -= outlineWidth;
+      glyphData.horizontalOffset += outlineOffset.x;
       if(lineIndex == 0u)
       {
         // Only need to add the vertical outline offset for the first line
         glyphData.verticalOffset -= outlineWidth;
+        glyphData.verticalOffset += outlineOffset.y;
       }
     }
     else if(style == Typesetter::STYLE_SHADOW)
@@ -1325,14 +1413,36 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con
       }
 
       // Calculate the positions of leftmost and rightmost glyphs in the current line
-      if(position.x < lineExtentLeft)
+      if(removeFrontInset)
       {
-        lineExtentLeft = position.x;
+        if(position.x < lineExtentLeft)
+        {
+          lineExtentLeft = position.x;
+        }
+      }
+      else
+      {
+        const float originPositionLeft = position.x - glyphInfo->xBearing;
+        if(originPositionLeft < lineExtentLeft)
+        {
+          lineExtentLeft = originPositionLeft;
+        }
       }
 
-      if(position.x + glyphInfo->width > lineExtentRight)
+      if(removeBackInset)
       {
-        lineExtentRight = position.x + glyphInfo->width;
+        if(position.x + glyphInfo->width > lineExtentRight)
+        {
+          lineExtentRight = position.x + glyphInfo->width;
+        }
+      }
+      else
+      {
+        const float originPositionRight = position.x - glyphInfo->xBearing + glyphInfo->advance;
+        if(originPositionRight > lineExtentRight)
+        {
+          lineExtentRight = originPositionRight;
+        }
       }
 
       // Retrieves the glyph's color.
@@ -1352,6 +1462,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con
         color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + (colorIndex - 1u));
       }
 
+      if(style == Typesetter::STYLE_NONE && cutoutEnabled)
+      {
+        // Temporarily adjust the transparency to 1.f
+        color.a = 1.f;
+      }
+
       // Premultiply alpha
       color.r *= color.a;
       color.g *= color.a;
@@ -1517,6 +1633,58 @@ Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelB
   return topPixelBuffer;
 }
 
+void Typesetter::SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha)
+{
+  // Assume that we always combine two RGBA images
+  // Jump with 4bytes for optimize runtime.
+  uint32_t* topBuffer    = reinterpret_cast<uint32_t*>(topPixelBuffer.GetBuffer());
+  uint32_t* bottomBuffer = reinterpret_cast<uint32_t*>(bottomPixelBuffer.GetBuffer());
+
+  if(topBuffer == NULL || bottomBuffer == NULL)
+  {
+    // Nothing to do if one of both buffers are empty.
+    return;
+  }
+
+  const uint32_t bufferSizeInt = bufferWidth * bufferHeight;
+
+  for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex)
+  {
+    uint32_t topBufferColor = *(topBuffer);
+    uint32_t bottomBufferColor = *(bottomBuffer);
+    uint8_t* __restrict__ topBufferColorBuffer = reinterpret_cast<uint8_t*>(&topBufferColor);
+    uint8_t* __restrict__ bottomBufferColorBuffer = reinterpret_cast<uint8_t*>(&bottomBufferColor);
+
+    uint8_t topAlpha = topBufferColorBuffer[3];
+    uint8_t bottomAlpha = 255 - topAlpha;
+
+    float tempTop[4], tempBottom[4];
+
+    // Return the transparency of the text to original.
+    tempTop[0] = static_cast<float>(topBufferColorBuffer[0]) * originAlpha;
+    tempTop[1] = static_cast<float>(topBufferColorBuffer[1]) * originAlpha;
+    tempTop[2] = static_cast<float>(topBufferColorBuffer[2]) * originAlpha;
+    tempTop[3] = static_cast<float>(topBufferColorBuffer[3]) * originAlpha;
+
+    // Manual blending.
+    tempBottom[0] = static_cast<float>(bottomBufferColorBuffer[0]) * static_cast<float>(bottomAlpha) / 255.f;
+    tempBottom[1] = static_cast<float>(bottomBufferColorBuffer[1]) * static_cast<float>(bottomAlpha) / 255.f;
+    tempBottom[2] = static_cast<float>(bottomBufferColorBuffer[2]) * static_cast<float>(bottomAlpha) / 255.f;
+    tempBottom[3] = static_cast<float>(bottomBufferColorBuffer[3]) * static_cast<float>(bottomAlpha) / 255.f;
+
+    bottomBufferColorBuffer[0] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[0] + tempTop[0])));
+    bottomBufferColorBuffer[1] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[1] + tempTop[1])));
+    bottomBufferColorBuffer[2] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[2] + tempTop[2])));
+    bottomBufferColorBuffer[3] = static_cast<uint8_t>(std::min(255u, static_cast<uint32_t>(tempBottom[3] + tempTop[3])));
+
+    *(bottomBuffer) = bottomBufferColor;
+
+    // Increase each buffer's pointer.
+    ++topBuffer;
+    ++bottomBuffer;
+  }
+}
+
 Typesetter::Typesetter(const ModelInterface* const model)
 : mModel(new ViewModel(model))
 {
index 296126e..7d268c9 100644 (file)
@@ -110,6 +110,61 @@ public:
    */
   PixelData Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888);
 
+  /**
+   * @brief After the Render, use the pixel information of the given cutoutBuffer to make the part where the pixel is drawn transparent.
+   *
+   * @param[in] size The renderer size.
+   * @param[in] textDirection The direction of the text.
+   * @param[in] cutoutBuffer The buffer to use pixel information to cutout.
+   * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
+   * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
+   * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+   * @param[in] originAlpha The original alpha of text.
+   *
+   * @return A pixel data with the text rendered.
+   */
+  PixelData RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer cutoutBuffer, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888, float originAlpha = 1.f);
+
+  /**
+   * @brief Renders the text, return as Devel::PixelBuffer.
+   *
+   * This function is used to obtain the PixelBuffer required for cutout.
+   *
+   * @param[in] size The renderer size.
+   * @param[in] textDirection The direction of the text.
+   * @param[in] cutoutBuffer The buffer to use pixel information to cutout.
+   * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
+   * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
+   * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+   *
+   * @return A pixel data with the text rendered.
+   */
+  Devel::PixelBuffer RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888);
+
+  /**
+   * @brief Create & draw the image buffer of single background color.
+   *
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   * @param[in] backgroundColor The backgroundColor of image buffer.
+   *
+   * @return An image buffer with the text.
+   */
+  Devel::PixelBuffer CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor);
+
+  /**
+   * @brief Set Mask for two pixel buffer.
+   *
+   * The alpha value of bottomPixelBuffer is decreased as the alpha value of topPixelBuffer is higher.
+   *
+   * @param[in, out] topPixelBuffer The top layer buffer.
+   * @param[in, out] bottomPixelBuffer The bottom layer buffer.
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   * @param[in] originAlpha The original alpha value of the text.
+   */
+  void SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha);
+
 private:
   /**
    * @brief Private constructor.
index 3799fc9..7e3a4e3 100644 (file)
@@ -285,6 +285,11 @@ void ViewModel::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRun
   mModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns);
 }
 
+const Vector2& ViewModel::GetOutlineOffset() const
+{
+  return mModel->GetOutlineOffset();
+}
+
 const Vector4& ViewModel::GetOutlineColor() const
 {
   return mModel->GetOutlineColor();
@@ -295,6 +300,11 @@ uint16_t ViewModel::GetOutlineWidth() const
   return mModel->GetOutlineWidth();
 }
 
+const float& ViewModel::GetOutlineBlurRadius() const
+{
+  return mModel->GetOutlineBlurRadius();
+}
+
 const Vector4& ViewModel::GetBackgroundColor() const
 {
   return mModel->GetBackgroundColor();
@@ -759,6 +769,31 @@ const Vector<FontDescriptionRun>& ViewModel::GetFontDescriptionRuns() const
   return mModel->GetFontDescriptionRuns();
 }
 
+bool ViewModel::IsRemoveFrontInset() const
+{
+  return mModel->IsRemoveFrontInset();
+}
+
+bool ViewModel::IsRemoveBackInset() const
+{
+  return mModel->IsRemoveBackInset();
+}
+
+bool ViewModel::IsCutoutEnabled() const
+{
+  return mModel->IsCutoutEnabled();
+}
+
+const bool ViewModel::IsBackgroundWithCutoutEnabled() const
+{
+  return mModel->IsBackgroundWithCutoutEnabled();
+}
+
+const Vector4& ViewModel::GetBackgroundColorWithCutout() const
+{
+  return mModel->GetBackgroundColorWithCutout();
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index 4de580d..dc7363d 100644 (file)
@@ -247,6 +247,11 @@ public:
   void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
 
   /**
+   * @copydoc ModelInterface::GetOutlineOffset()
+   */
+  const Vector2& GetOutlineOffset() const override;
+
+  /**
    * @copydoc ModelInterface::GetOutlineColor()
    */
   const Vector4& GetOutlineColor() const override;
@@ -257,6 +262,11 @@ public:
   uint16_t GetOutlineWidth() const override;
 
   /**
+   * @copydoc ModelInterface::GetOutlineBlurRadius()
+   */
+  const float& GetOutlineBlurRadius() const override;
+
+  /**
    * @copydoc ModelInterface::GetBackgroundColor()
    */
   const Vector4& GetBackgroundColor() const override;
@@ -378,6 +388,31 @@ public:
    */
   const Vector<FontDescriptionRun>& GetFontDescriptionRuns() const override;
 
+  /**
+   * @copydoc ModelInterface::IsRemoveFrontInset()
+   */
+  bool IsRemoveFrontInset() const override;
+
+  /**
+   * @copydoc ModelInterface::IsRemoveBackInset()
+   */
+  bool IsRemoveBackInset() const override;
+
+  /**
+   * @copydoc ModelInterface::IsCutoutEnabled()
+   */
+  bool IsCutoutEnabled() const override;
+
+  /**
+   * @copydoc ModelInterface::IsBackgroundWithCutoutEnabled()
+   */
+  const bool IsBackgroundWithCutoutEnabled() const override;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColorWithCutout()
+   */
+  const Vector4& GetBackgroundColorWithCutout() const override;
+
 private:
   const ModelInterface* const mModel;                           ///< Pointer to the text's model.
   Vector<GlyphInfo>           mElidedGlyphs;                    ///< Stores the glyphs of the elided text.
index f89846e..ffbef1e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_SPANS_CONTAINER_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -121,16 +121,6 @@ private:
 
 } // namespace Toolkit
 
-// Allow SpanRangesContainer to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::SpanRangesContainer> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::SpanRangesContainer>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANS_CONTAINER_IMPL_H
index 0b56043..40b388a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -102,16 +102,6 @@ inline const Internal::Spannable& GetImplementation(const Dali::Toolkit::Text::S
 
 } // namespace Toolkit
 
-// Allow Spannable to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::Spannable> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::Spannable>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_IMPL_H
index 5ecb823..5dccab4 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_STRING_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -144,16 +144,6 @@ inline const Internal::SpannableString& GetImplementation(const Dali::Toolkit::T
 
 } // namespace Toolkit
 
-// Allow SpannableString to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::SpannableString> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::SpannableString>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANNABLE_STRING_IMPL_H
index 4e5a8c7..e6c18cd 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_SPANNED_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -103,16 +103,6 @@ inline const Internal::Spanned& GetImplementation(const Dali::Toolkit::Text::Spa
 
 } // namespace Toolkit
 
-// Allow Spanned to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::Spanned> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::Spanned>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_SPANNED_IMPL_H
index 5f01524..cd2f850 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_BASE_SPAN_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -116,16 +116,6 @@ inline const Internal::BaseSpan& GetImplementation(const Dali::Toolkit::Text::Ba
 
 } // namespace Toolkit
 
-// Allow BaseSpan to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::BaseSpan> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::BaseSpan>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_BASE_SPAN_IMPL_H
index d04883b..27312b7 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_CHARACTER_SEQUENCE_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -109,16 +109,6 @@ inline const Internal::CharacterSequence& GetImplementation(const Dali::Toolkit:
 
 } // namespace Toolkit
 
-// Allow AbstractStyleSpan to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::CharacterSequence> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::CharacterSequence>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_CHARACTER_SEQUENCE_IMPL_H
index 8b0f0d2..b4e6c1a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_RANGE_IMPL_H
 
 /*
- * Copyright (c) 2022 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.
@@ -126,16 +126,6 @@ inline const Internal::Range& GetImplementation(const Dali::Toolkit::Text::Range
 
 } // namespace Toolkit
 
-// Allow Range to be treated as a POD type
-template<>
-struct TypeTraits<Dali::Toolkit::Text::Internal::Range> : public Dali::BasicTypes<Dali::Toolkit::Text::Internal::Range>
-{
-  enum
-  {
-    IS_TRIVIAL_TYPE = true
-  };
-};
-
 } // namespace Dali
 
 #endif // DALI_TOOLKIT_INTERNAL_TEXT_RANGE_IMPL_H
index 2bf1398..be4cbfa 100644 (file)
@@ -229,7 +229,11 @@ bool ParseOutlineProperties(const Property::Map& underlinePropertiesMap,
                             bool&                colorDefined,
                             Vector4&             color,
                             bool&                widthDefined,
-                            uint16_t&            width)
+                            uint16_t&            width,
+                            bool&                offsetDefined,
+                            Vector2&             offset,
+                            bool&                blurRadiusDefined,
+                            float&               blurRadius)
 {
   const unsigned int numberOfItems = underlinePropertiesMap.Count();
 
@@ -250,6 +254,36 @@ bool ParseOutlineProperties(const Property::Map& underlinePropertiesMap,
       widthDefined = true;
       width        = static_cast<uint16_t>(valueGet.second.Get<float>());
     }
+    else if((DevelText::Outline::Property::OFFSET == valueGet.first.indexKey) || (OFFSET_KEY == valueGet.first.stringKey))
+    {
+      /// Offset key.
+      offsetDefined = true;
+
+      if(valueGet.second.GetType() == Dali::Property::STRING)
+      {
+        const std::string offsetStr = valueGet.second.Get<std::string>();
+        StringToVector2(offsetStr.c_str(), offsetStr.size(), offset);
+      }
+      else
+      {
+        offset = valueGet.second.Get<Vector2>();
+      }
+    }
+    else if((DevelText::Outline::Property::BLUR_RADIUS == valueGet.first.indexKey) || (BLUR_RADIUS_KEY == valueGet.first.stringKey))
+    {
+      /// Blur radius key.
+      blurRadiusDefined = true;
+
+      if(valueGet.second.GetType() == Dali::Property::STRING)
+      {
+        const std::string blurRadiusStr = valueGet.second.Get<std::string>();
+        blurRadius                      = StringToFloat(blurRadiusStr.c_str());
+      }
+      else
+      {
+        blurRadius = valueGet.second.Get<float>();
+      }
+    }
   }
 
   return 0u == numberOfItems;
@@ -752,10 +786,14 @@ bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value
       {
         const Property::Map& propertiesMap = value.Get<Property::Map>();
 
-        bool     colorDefined = false;
+        bool     colorDefined  = false;
         Vector4  color;
-        bool     widthDefined = false;
-        uint16_t width        = 0u;
+        bool     widthDefined  = false;
+        uint16_t width         = 0u;
+        bool     offsetDefined = false;
+        Vector2  offset;
+        bool     blurRadiusDefined = false;
+        float    blurRadius;
 
         bool empty = true;
 
@@ -776,7 +814,11 @@ bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value
                                          colorDefined,
                                          color,
                                          widthDefined,
-                                         width);
+                                         width,
+                                         offsetDefined,
+                                         offset,
+                                         blurRadiusDefined,
+                                         blurRadius);
 
           controller->OutlineSetByString(false);
         }
@@ -795,6 +837,18 @@ bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value
             controller->SetOutlineWidth(width);
             update = true;
           }
+
+          if(offsetDefined && (controller->GetOutlineOffset() != offset))
+          {
+            controller->SetOutlineOffset(offset);
+            update = true;
+          }
+
+          if(blurRadiusDefined && (!Dali::Equals(controller->GetOutlineBlurRadius(), blurRadius)))
+          {
+            controller->SetOutlineBlurRadius(blurRadius);
+            update = true;
+          }
         }
         else
         {
@@ -835,12 +889,16 @@ void GetOutlineProperties(ControllerPtr controller, Property::Value& value, Effe
         }
         else
         {
-          const Vector4& color = controller->GetOutlineColor();
-          const uint16_t width = controller->GetOutlineWidth();
+          const Vector4& color      = controller->GetOutlineColor();
+          const uint16_t width      = controller->GetOutlineWidth();
+          const Vector2& offset     = controller->GetOutlineOffset();
+          const float&   blurRadius = controller->GetOutlineBlurRadius();
 
           Property::Map map;
           map.Insert(COLOR_KEY, color);
           map.Insert(WIDTH_KEY, static_cast<int>(width));
+          map.Insert(OFFSET_KEY, offset);
+          map.Insert(BLUR_RADIUS_KEY, blurRadius);
 
           value = map;
 
index bd34ff8..ba9f6ca 100644 (file)
@@ -322,6 +322,13 @@ public:
   virtual void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const = 0;
 
   /**
+   * @brief Retrieves the outline offset.
+   *
+   * @return The outline offset.
+   */
+  virtual const Vector2& GetOutlineOffset() const = 0;
+
+  /**
    * @brief Retrieve the outline color.
    *
    * @return The outline color.
@@ -336,6 +343,13 @@ public:
   virtual uint16_t GetOutlineWidth() const = 0;
 
   /**
+   * @brief Retrieve the outline blur radius.
+   *
+   * @return The outline blur radius.
+   */
+  virtual const float& GetOutlineBlurRadius() const = 0;
+
+  /**
    * @brief Retrieves the background color.
    *
    * @return The background color.
@@ -494,6 +508,41 @@ public:
    * @return The reference for font description runs.
    */
   virtual const Vector<FontDescriptionRun>& GetFontDescriptionRuns() const = 0;
+
+  /**
+   * @brief Retrieves the remove front inset is enabled or not.
+   *
+   * @return boolean if it is enabled.
+   */
+  virtual bool IsRemoveFrontInset() const = 0;
+
+  /**
+   * @brief Retrieves the remove back inset is enabled or not.
+   *
+   * @return boolean if it is enabled.
+   */
+  virtual bool IsRemoveBackInset() const = 0;
+
+  /**
+   * @brief Retrieves the cutout is enabled or not.
+   *
+   * @return boolean if it is enabled.
+   */
+  virtual bool IsCutoutEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the background with cutout is enabled or not.
+   *
+   * @return boolean if it is enabled.
+   */
+  virtual const bool IsBackgroundWithCutoutEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the color of the background with cutout.
+   *
+   * @return The color of the background with cutout.
+   */
+  virtual const Vector4& GetBackgroundColorWithCutout() const = 0;
 };
 
 } // namespace Text
index ae0dd7c..bbe126b 100644 (file)
@@ -227,6 +227,11 @@ void Model::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunInde
   mVisualModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns);
 }
 
+const Vector2& Model::GetOutlineOffset() const
+{
+  return mVisualModel->GetOutlineOffset();
+}
+
 const Vector4& Model::GetOutlineColor() const
 {
   return mVisualModel->GetOutlineColor();
@@ -237,6 +242,11 @@ uint16_t Model::GetOutlineWidth() const
   return mVisualModel->GetOutlineWidth();
 }
 
+const float& Model::GetOutlineBlurRadius() const
+{
+  return mVisualModel->mOutlineBlurRadius;
+}
+
 const Vector4& Model::GetBackgroundColor() const
 {
   return mVisualModel->GetBackgroundColor();
@@ -346,6 +356,31 @@ const Vector<FontDescriptionRun>& Model::GetFontDescriptionRuns() const
   return mLogicalModel->mFontDescriptionRuns;
 }
 
+bool Model::IsRemoveFrontInset() const
+{
+  return mRemoveFrontInset;
+}
+
+bool Model::IsRemoveBackInset() const
+{
+  return mRemoveBackInset;
+}
+
+bool Model::IsCutoutEnabled() const
+{
+  return mVisualModel->IsCutoutEnabled();
+}
+
+const bool Model::IsBackgroundWithCutoutEnabled() const
+{
+  return mVisualModel->IsBackgroundWithCutoutEnabled();
+}
+
+const Vector4& Model::GetBackgroundColorWithCutout() const
+{
+  return mVisualModel->GetBackgroundColorWithCutout();
+}
+
 Model::Model()
 : mLogicalModel(),
   mVisualModel(),
index e738784..5661035 100644 (file)
@@ -245,6 +245,11 @@ public:
   void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
 
   /**
+   * @copydoc ModelInterface::GetOutlineOffset()
+   */
+  const Vector2& GetOutlineOffset() const override;
+
+  /**
    * @copydoc ModelInterface::GetOutlineColor()
    */
   const Vector4& GetOutlineColor() const override;
@@ -255,6 +260,11 @@ public:
   uint16_t GetOutlineWidth() const override;
 
   /**
+   * @copydoc ModelInterface::GetOutlineBlurRadius()
+   */
+  const float& GetOutlineBlurRadius() const override;
+
+  /**
    * @copydoc ModelInterface::GetBackgroundColor()
    */
   const Vector4& GetBackgroundColor() const override;
@@ -364,6 +374,31 @@ public:
    */
   const Vector<FontDescriptionRun>& GetFontDescriptionRuns() const override;
 
+  /**
+   * @copydoc ModelInterface::IsRemoveFrontInset()
+   */
+  bool IsRemoveFrontInset() const override;
+
+  /**
+   * @copydoc ModelInterface::IsRemoveBackInset()
+   */
+  bool IsRemoveBackInset() const override;
+
+  /**
+   * @copydoc ModelInterface::IsCutoutEnabled()
+   */
+  bool IsCutoutEnabled() const override;
+
+  /**
+   * @copydoc ModelInterface::IsBackgroundWithCutoutEnabled()
+   */
+  const bool IsBackgroundWithCutoutEnabled() const override;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColorWithCutout()
+   */
+  const Vector4& GetBackgroundColorWithCutout() const override;
+
 private: // Private contructors & copy operator.
   /**
    * @brief Private constructor.
index 59bb09f..08e08c8 100644 (file)
@@ -144,18 +144,19 @@ void TextScroller::SetStopMode(TextLabel::AutoScrollStopMode::Type stopMode)
 
 void TextScroller::StopScrolling()
 {
-  if(mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING)
+  if(IsScrolling())
   {
     switch(mStopMode)
     {
       case TextLabel::AutoScrollStopMode::IMMEDIATE:
       {
+        mIsStop = true;
         mScrollAnimation.Stop();
-        mScrollerInterface.ScrollingFinished();
         break;
       }
       case TextLabel::AutoScrollStopMode::FINISH_LOOP:
       {
+        mIsStop = true;
         mScrollAnimation.SetLoopCount(1); // As animation already playing this allows the current animation to finish instead of trying to stop mid-way
         break;
       }
@@ -171,6 +172,16 @@ void TextScroller::StopScrolling()
   }
 }
 
+bool TextScroller::IsStop()
+{
+  return mIsStop;
+}
+
+bool TextScroller::IsScrolling()
+{
+  return (mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING);
+}
+
 TextLabel::AutoScrollStopMode::Type TextScroller::GetStopMode() const
 {
   return mStopMode;
@@ -183,7 +194,8 @@ TextScroller::TextScroller(ScrollerInterface& scrollerInterface)
   mLoopCount(1),
   mLoopDelay(0.0f),
   mWrapGap(0.0f),
-  mStopMode(TextLabel::AutoScrollStopMode::FINISH_LOOP)
+  mStopMode(TextLabel::AutoScrollStopMode::FINISH_LOOP),
+  mIsStop(false)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n");
 }
@@ -195,7 +207,6 @@ TextScroller::~TextScroller()
 void TextScroller::SetParameters(Actor scrollingTextActor, Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& textureSize, const float wrapGap, CharacterDirection direction, HorizontalAlignment::Type horizontalAlignment, VerticalAlignment::Type verticalAlignment)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters controlSize[%f,%f] textureSize[%f,%f] direction[%d]\n", controlSize.x, controlSize.y, textureSize.x, textureSize.y, direction);
-
   mRenderer = renderer;
 
   float animationProgress = 0.0f;
@@ -209,7 +220,7 @@ void TextScroller::SetParameters(Actor scrollingTextActor, Renderer renderer, Te
       if(mLoopCount > 0) // If not a ininity loop, then calculate remained loop
       {
         remainedLoop = mLoopCount - (mScrollAnimation.GetCurrentLoop());
-        remainedLoop = (remainedLoop <= 0 ? 1 : remainedLoop);
+        remainedLoop = mIsStop ? 1 : (remainedLoop <= 0 ? 1 : remainedLoop);
       }
     }
     mScrollAnimation.Clear();
@@ -269,6 +280,7 @@ void TextScroller::SetParameters(Actor scrollingTextActor, Renderer renderer, Te
 void TextScroller::AutoScrollAnimationFinished(Dali::Animation& animation)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n");
+  mIsStop = false;
   mScrollerInterface.ScrollingFinished();
 
   // Revert to the original shader and texture after scrolling
@@ -282,7 +294,6 @@ void TextScroller::AutoScrollAnimationFinished(Dali::Animation& animation)
 void TextScroller::StartScrolling(Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::StartScrolling scrollAmount[%f] scrollDuration[%f], loop[%d] speed[%d]\n", scrollAmount, scrollDuration, loopCount, mScrollSpeed);
-
   Shader shader    = mRenderer.GetShader();
   mScrollAnimation = Animation::New(scrollDuration);
   mScrollAnimation.AnimateTo(Property(shader, mScrollDeltaIndex), scrollAmount, TimePeriod(mLoopDelay, scrollDuration));
@@ -290,6 +301,8 @@ void TextScroller::StartScrolling(Actor scrollingTextActor, float scrollAmount,
   mScrollAnimation.SetLoopCount(loopCount);
   mScrollAnimation.FinishedSignal().Connect(this, &TextScroller::AutoScrollAnimationFinished);
   mScrollAnimation.Play();
+
+  mIsStop = false;
 }
 
 } // namespace Text
index b93c2d2..99a4936 100644 (file)
@@ -129,6 +129,16 @@ public:
   void StopScrolling();
 
   /**
+   * @brief Whether the stop scrolling has been triggered or not.
+   */
+  bool IsStop();
+
+  /**
+   * @brief Whether the scroll animation is playing or not.
+   */
+  bool IsScrolling();
+
+  /**
    * @brief Get the mode of scrolling stop
    * @return stopMode type when text scrolling is stoped.
    */
@@ -179,6 +189,7 @@ private:
   float                               mLoopDelay;   ///< Time delay of loop start
   float                               mWrapGap;     ///< Gap before text wraps around when scrolling
   TextLabel::AutoScrollStopMode::Type mStopMode;    ///< Stop mode of scrolling text, when loop count is 0.
+  bool                                mIsStop : 1;  ///< Whether the stop scrolling has been triggered or not.
 
 }; // TextScroller class
 
index 24fcfff..5fbbfea 100644 (file)
@@ -248,6 +248,13 @@ public:
                                 Length              numberOfRuns) const = 0;
 
   /**
+   * @brief Retrieves the outline offset.
+   *
+   * @return The outline offset.
+   */
+  virtual const Vector2& GetOutlineOffset() const = 0;
+
+  /**
    * @brief Retrieve the outline color.
    *
    * @return The outline color.
@@ -385,6 +392,13 @@ public:
    * @return GetGlyphsToCharacters.
    */
   virtual const Vector<CharacterIndex>& GetGlyphsToCharacters() const = 0;
+
+  /**
+   * @brief Returns whether cutout is enabled or not.
+   *
+   * @return The cutout state.
+   */
+  virtual bool IsCutoutEnabled() const = 0;
 };
 
 } // namespace Text
index d71000b..3b678dd 100644 (file)
@@ -845,6 +845,18 @@ void View::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
   }
 }
 
+const Vector2& View::GetOutlineOffset() const
+{
+// TODO : We should support outline offset to editable text.
+/*
+  if(mImpl->mVisualModel)
+  {
+    return mImpl->mVisualModel->GetOutlineOffset();
+  }
+*/
+  return Vector2::ZERO;
+}
+
 const Vector4& View::GetOutlineColor() const
 {
   if(mImpl->mVisualModel)
@@ -1012,4 +1024,13 @@ const Vector<CharacterIndex>& View::GetGlyphsToCharacters() const
   return mImpl->mVisualModel->GetGlyphsToCharacters();
 }
 
+bool View::IsCutoutEnabled() const
+{
+  if(mImpl->mVisualModel)
+  {
+    return mImpl->mVisualModel->IsCutoutEnabled();
+  }
+  return false;
+}
+
 } // namespace Dali::Toolkit::Text
index 5bf55e1..d141f4b 100644 (file)
@@ -187,6 +187,11 @@ public:
                                 Length              numberOfRuns) const;
 
   /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineOffset()
+   */
+  const Vector2& GetOutlineOffset() const override;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineColor()
    */
   const Vector4& GetOutlineColor() const override;
@@ -283,6 +288,11 @@ public:
    */
   const Vector<CharacterIndex>& GetGlyphsToCharacters() const override;
 
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::IsCutoutEnabled()
+   */
+  bool IsCutoutEnabled() const override;
+
 private:
   // Undefined
   View(const View& handle);
index c79e5a9..3fdd6b8 100644 (file)
@@ -381,11 +381,21 @@ void VisualModel::SetUnderlineColor(const Vector4& color)
   mUnderlineColorSet = true;
 }
 
+void VisualModel::SetOutlineOffset(const Vector2& outlineOffset)
+{
+  mOutlineOffset = outlineOffset;
+}
+
 void VisualModel::SetOutlineColor(const Vector4& color)
 {
   mOutlineColor = color;
 }
 
+void VisualModel::SetOutlineBlurRadius(const float& outlineBlurRadius)
+{
+  mOutlineBlurRadius = outlineBlurRadius;
+}
+
 void VisualModel::SetUnderlineEnabled(bool enabled)
 {
   mUnderlineEnabled = enabled;
@@ -506,11 +516,21 @@ const Vector4& VisualModel::GetUnderlineColor() const
   return mUnderlineColor;
 }
 
+const Vector2& VisualModel::GetOutlineOffset() const
+{
+  return mOutlineOffset;
+}
+
 const Vector4& VisualModel::GetOutlineColor() const
 {
   return mOutlineColor;
 }
 
+const float& VisualModel::GetOutlineBlurRadius() const
+{
+  return mOutlineBlurRadius;
+}
+
 bool VisualModel::IsUnderlineEnabled() const
 {
   return mUnderlineEnabled;
@@ -645,6 +665,36 @@ const Vector<CharacterIndex>& VisualModel::GetGlyphsToCharacters() const
   return mGlyphsToCharacters;
 }
 
+void VisualModel::SetCutoutEnabled(bool enable)
+{
+  mCutoutEnabled = enable;
+}
+
+bool VisualModel::IsCutoutEnabled() const
+{
+  return mCutoutEnabled;
+}
+
+void VisualModel::SetBackgroundWithCutoutEnabled(bool enable)
+{
+  mBackgroundWithCutoutEnabled = enable;
+}
+
+bool VisualModel::IsBackgroundWithCutoutEnabled() const
+{
+  return mBackgroundWithCutoutEnabled;
+}
+
+void VisualModel::SetBackgroundColorWithCutout(const Vector4& color)
+{
+  mBackgroundColorWithCutout = color;
+}
+
+const Vector4& VisualModel::GetBackgroundColorWithCutout() const
+{
+  return mBackgroundColorWithCutout;
+}
+
 VisualModel::~VisualModel()
 {
 }
@@ -665,12 +715,14 @@ VisualModel::VisualModel()
   mStrikethroughColor(Color::BLACK),
   mControlSize(),
   mShadowOffset(),
+  mOutlineOffset(),
   mUnderlineHeight(0.0f),
   mStrikethroughHeight(0.0f),
   mUnderlineType(Text::Underline::SOLID),
   mDashedUnderlineWidth(2.0f),
   mDashedUnderlineGap(1.0f),
   mShadowBlurRadius(0.0f),
+  mOutlineBlurRadius(0.0f),
   mOutlineWidth(0u),
   mNaturalSize(),
   mLayoutSize(),
@@ -687,8 +739,9 @@ VisualModel::VisualModel()
   mBackgroundEnabled(false),
   mMarkupProcessorEnabled(false),
   mStrikethroughEnabled(false),
-  mCharacterSpacing(0.0f)
-
+  mCharacterSpacing(0.0f),
+  mCutoutEnabled(false),
+  mBackgroundWithCutoutEnabled(false)
 {
 }
 
index 9dae2cf..7ef55b5 100644 (file)
@@ -384,6 +384,13 @@ public:
   Length GetNumberOfUnderlineRuns() const;
 
   /**
+   * @brief Sets the text's outline offset.
+   *
+   * @param[in] outlineOffset The outline offset.
+   */
+  void SetOutlineOffset(const Vector2& outlineOffset);
+
+  /**
    * @brief Set the outline color.
    *
    * @param[in] color color of outline.
@@ -391,6 +398,13 @@ public:
   void SetOutlineColor(const Vector4& color);
 
   /**
+   * @brief Retrieves the text's outline offset.
+   *
+   * @return The text's outline offset.
+   */
+  const Vector2& GetOutlineOffset() const;
+
+  /**
    * @brief Retrieve the outline color.
    *
    * @return The outline color.
@@ -412,6 +426,20 @@ public:
   uint16_t GetOutlineWidth() const;
 
   /**
+   * @brief Set the outline blur radius.
+   *
+   * @param[in] outlineBlurRadius The outline blur radius, 0,0 indicates no blur.
+   */
+  void SetOutlineBlurRadius(const float& outlineBlurRadius);
+
+  /**
+   * @brief Retrieve the outline blur radius.
+   *
+   * @return The outline blur radius.
+   */
+  const float& GetOutlineBlurRadius() const;
+
+  /**
    * @brief Sets the text's background color.
    *
    * @param[in] color The text's background color.
@@ -634,6 +662,48 @@ public:
    */
   const Vector<CharacterSpacingGlyphRun>& GetCharacterSpacingGlyphRuns() const;
 
+  /**
+   * @brief Sets the cutout flag.
+   *
+   * @param[in] enable true if cutouted.
+   */
+  void SetCutoutEnabled(bool enable);
+
+  /**
+   * @brief Returns whether the text is cutouted or not.
+   *
+   * @return cutout state.
+   */
+  bool IsCutoutEnabled() const;
+
+  /**
+   * @brief Sets the background with cutout flag.
+   *
+   * @param[in] enable true if background enabled.
+   */
+  void SetBackgroundWithCutoutEnabled(bool enable);
+
+  /**
+   * @brief Returns whether the text is cutouted or not.
+   *
+   * @return True if enabled.
+   */
+  bool IsBackgroundWithCutoutEnabled() const;
+
+  /**
+   * @brief Sets the Color of background with cutout.
+   *
+   * @param[in] color The color to set.
+   */
+  void SetBackgroundColorWithCutout(const Vector4& color);
+
+  /**
+   * @brief Retrieves the Color of background with cutout.
+   *
+   * @return The color.
+   */
+  const Vector4& GetBackgroundColorWithCutout() const;
+
 protected:
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -653,35 +723,38 @@ private:
   VisualModel& operator=(const VisualModel& handle);
 
 public:
-  Vector<GlyphInfo>                mGlyphs;                 ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
-  Vector<CharacterIndex>           mGlyphsToCharacters;     ///< For each glyph, the index of the first character.
-  Vector<GlyphIndex>               mCharactersToGlyph;      ///< For each character, the index of the first glyph.
-  Vector<Length>                   mCharactersPerGlyph;     ///< For each glyph, the number of characters that form the glyph.
-  Vector<Length>                   mGlyphsPerCharacter;     ///< For each character, the number of glyphs that are shaped.
-  Vector<Vector2>                  mGlyphPositions;         ///< For each glyph, the position.
-  Vector<LineRun>                  mLines;                  ///< The laid out lines.
-  Vector<UnderlinedGlyphRun>       mUnderlineRuns;          ///< Runs of glyphs that are underlined.
-  Vector<Vector4>                  mColors;                 ///< Colors of the glyphs.
-  Vector<ColorIndex>               mColorIndices;           ///< Indices to the vector of colors for each glyphs.
-  Vector<Vector4>                  mBackgroundColors;       ///< Background colors of the glyphs.
-  Vector<ColorIndex>               mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
-  Vector4                          mTextColor;              ///< The text color
-  Vector4                          mShadowColor;            ///< Color of drop shadow
-  Vector4                          mUnderlineColor;         ///< Color of underline
-  Vector4                          mOutlineColor;           ///< Color of outline
-  Vector4                          mBackgroundColor;        ///< Color of text background
-  Vector4                          mStrikethroughColor;     ///< Color of text background
-  Size                             mControlSize;            ///< The size of the UI control.
-  Vector2                          mShadowOffset;           ///< Offset for drop shadow, 0 indicates no shadow
-  float                            mUnderlineHeight;        ///< Fixed height for underline to override font metrics.
-  float                            mStrikethroughHeight;    ///< Fixed height for strikethrough to override font metrics.
-  Text::Underline::Type            mUnderlineType;          ///< The type of the underline.
-  float                            mDashedUnderlineWidth;   ///< The width of the dashes of the dashed underline.
-  float                            mDashedUnderlineGap;     ///< The gap between the dashes of the dashed underline.
-  float                            mShadowBlurRadius;       ///< Blur radius of shadow, 0 indicates no blur.
-  uint16_t                         mOutlineWidth;           ///< Width of outline.
-  Vector<StrikethroughGlyphRun>    mStrikethroughRuns;      ///< Runs of glyphs that have strikethrough.
-  Vector<CharacterSpacingGlyphRun> mCharacterSpacingRuns;   ///< Runs of glyphs that have character-spacing.
+  Vector<GlyphInfo>                mGlyphs;                     ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
+  Vector<CharacterIndex>           mGlyphsToCharacters;         ///< For each glyph, the index of the first character.
+  Vector<GlyphIndex>               mCharactersToGlyph;          ///< For each character, the index of the first glyph.
+  Vector<Length>                   mCharactersPerGlyph;         ///< For each glyph, the number of characters that form the glyph.
+  Vector<Length>                   mGlyphsPerCharacter;         ///< For each character, the number of glyphs that are shaped.
+  Vector<Vector2>                  mGlyphPositions;             ///< For each glyph, the position.
+  Vector<LineRun>                  mLines;                      ///< The laid out lines.
+  Vector<UnderlinedGlyphRun>       mUnderlineRuns;              ///< Runs of glyphs that are underlined.
+  Vector<Vector4>                  mColors;                     ///< Colors of the glyphs.
+  Vector<ColorIndex>               mColorIndices;               ///< Indices to the vector of colors for each glyphs.
+  Vector<Vector4>                  mBackgroundColors;           ///< Background colors of the glyphs.
+  Vector<ColorIndex>               mBackgroundColorIndices;     ///< Indices to the vector of background colors for each glyphs.
+  Vector4                          mTextColor;                  ///< The text color
+  Vector4                          mShadowColor;                ///< Color of drop shadow
+  Vector4                          mUnderlineColor;             ///< Color of underline
+  Vector4                          mOutlineColor;               ///< Color of outline
+  Vector4                          mBackgroundColor;            ///< Color of text background
+  Vector4                          mStrikethroughColor;         ///< Color of text background
+  Size                             mControlSize;                ///< The size of the UI control.
+  Vector2                          mShadowOffset;               ///< Offset for drop shadow, 0 indicates no shadow
+  Vector2                          mOutlineOffset;              ///< Offset for outline
+  float                            mUnderlineHeight;            ///< Fixed height for underline to override font metrics.
+  float                            mStrikethroughHeight;        ///< Fixed height for strikethrough to override font metrics.
+  Text::Underline::Type            mUnderlineType;              ///< The type of the underline.
+  float                            mDashedUnderlineWidth;       ///< The width of the dashes of the dashed underline.
+  float                            mDashedUnderlineGap;         ///< The gap between the dashes of the dashed underline.
+  float                            mShadowBlurRadius;           ///< Blur radius of shadow, 0 indicates no blur.
+  float                            mOutlineBlurRadius;      ///< Blur radius of outline, 0 indicates no blur.
+  uint16_t                         mOutlineWidth;               ///< Width of outline.
+  Vector<StrikethroughGlyphRun>    mStrikethroughRuns;          ///< Runs of glyphs that have strikethrough.
+  Vector<CharacterSpacingGlyphRun> mCharacterSpacingRuns;       ///< Runs of glyphs that have character-spacing.
+  Vector4                          mBackgroundColorWithCutout;  ///< Background color with cutout.
 
 private:
   Size mNaturalSize;    ///< Size of the text with no line wrapping.
@@ -699,13 +772,15 @@ private:
   bool                              mTextElideEnabled : 1;            ///< Whether the text's elide is enabled.
 
 public:
-  bool       mUnderlineEnabled : 1;       ///< Underline enabled flag
-  bool       mUnderlineColorSet : 1;      ///< Has the underline color been explicitly set?
-  bool       mBackgroundEnabled : 1;      ///< Background enabled flag
-  bool       mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
-  HyphenInfo mHyphen;                     ///< Contains hyphen glyph info & the character index to draw hyphen after.
-  bool       mStrikethroughEnabled : 1;   ///< Strikethrough enabled flag
-  float      mCharacterSpacing;           ///< Contains the value of the character spacing.
+  bool       mUnderlineEnabled : 1;             ///< Underline enabled flag
+  bool       mUnderlineColorSet : 1;            ///< Has the underline color been explicitly set?
+  bool       mBackgroundEnabled : 1;            ///< Background enabled flag
+  bool       mMarkupProcessorEnabled : 1;       ///< Markup-processor enabled flag
+  HyphenInfo mHyphen;                           ///< Contains hyphen glyph info & the character index to draw hyphen after.
+  bool       mStrikethroughEnabled : 1;         ///< Strikethrough enabled flag
+  float      mCharacterSpacing;                 ///< Contains the value of the character spacing.
+  bool       mCutoutEnabled : 1;                ///< Cutout enabled flag
+  bool       mBackgroundWithCutoutEnabled : 1;  ///< Background with cutout enabled flag.
 };
 
 } // namespace Text
index ef2e759..f3b5028 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -102,7 +102,6 @@ TextureManager::MaskingData::MaskingData()
 TextureManager::TextureManager(bool loadYuvPlanes)
 : mTextureCacheManager(),
   mAsyncLoader(std::unique_ptr<TextureAsyncLoadingHelper>(new TextureAsyncLoadingHelper(*this))),
-  mLifecycleObservers(),
   mLoadQueue(),
   mLoadingQueueTextureId(INVALID_TEXTURE_ID),
   mRemoveQueue(),
@@ -120,11 +119,6 @@ TextureManager::~TextureManager()
     Adaptor::Get().UnregisterProcessor(*this, true);
     mRemoveProcessorRegistered = false;
   }
-
-  for(auto iter = mLifecycleObservers.Begin(), endIter = mLifecycleObservers.End(); iter != endIter; ++iter)
-  {
-    (*iter)->TextureManagerDestroyed();
-  }
 }
 
 TextureSet TextureManager::LoadAnimatedImageTexture(
@@ -872,29 +866,6 @@ void TextureManager::LoadImageSynchronously(
   }
 }
 
-void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer)
-{
-  // make sure an observer doesn't observe the same object twice
-  // otherwise it will get multiple calls to ObjectDestroyed()
-  DALI_ASSERT_DEBUG(mLifecycleObservers.End() == std::find(mLifecycleObservers.Begin(), mLifecycleObservers.End(), &observer));
-  mLifecycleObservers.PushBack(&observer);
-}
-
-void TextureManager::RemoveObserver(TextureManager::LifecycleObserver& observer)
-{
-  // Find the observer...
-  auto endIter = mLifecycleObservers.End();
-  for(auto iter = mLifecycleObservers.Begin(); iter != endIter; ++iter)
-  {
-    if((*iter) == &observer)
-    {
-      mLifecycleObservers.Erase(iter);
-      break;
-    }
-  }
-  DALI_ASSERT_DEBUG(endIter != mLifecycleObservers.End());
-}
-
 void TextureManager::LoadOrQueueTexture(TextureManager::TextureInfo& textureInfo, TextureUploadObserver* observer)
 {
   switch(textureInfo.loadState)
index fdae67a..f460893 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_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.
@@ -85,17 +85,6 @@ public:
   using MaskingDataPointer = std::unique_ptr<MaskingData>;
 
   /**
-   * Class to provide lifecycle event on destruction of texture manager.
-   */
-  struct LifecycleObserver
-  {
-    /**
-     * Called shortly before the texture manager is destroyed.
-     */
-    virtual void TextureManagerDestroyed() = 0;
-  };
-
-  /**
    * Constructor.
    *
    * @param[in] loadYuvPlanes Whether we allow to load YuvPlanes or not. Default is false.
@@ -228,19 +217,6 @@ public:
     TextureManager::MultiplyOnLoad&    preMultiplyOnLoad);
 
   /**
-   * Add an observer to the object.
-   * @param[in] observer The observer to add.
-   */
-  void AddObserver(TextureManager::LifecycleObserver& observer);
-
-  /**
-   * Remove an observer from the object
-   * @pre The observer has already been added.
-   * @param[in] observer The observer to remove.
-   */
-  void RemoveObserver(TextureManager::LifecycleObserver& observer);
-
-  /**
    * @brief Returns the geometry associated with texture.
    * @param[in] textureId Id of the texture
    * @param[out] frontElements number of front elements
@@ -675,8 +651,7 @@ private:
 private:                                    // Member Variables:
   TextureCacheManager mTextureCacheManager; ///< Manager the life-cycle and caching of Textures
 
-  std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader;        ///< The Asynchronous image loader used to provide all local async loads
-  Dali::Vector<LifecycleObserver*>           mLifecycleObservers; ///< Lifecycle observers of texture manager
+  std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader; ///< The Asynchronous image loader used to provide all local async loads
 
   Dali::Vector<QueueElement> mLoadQueue;             ///< Queue of textures to load after NotifyObservers
   TextureManager::TextureId  mLoadingQueueTextureId; ///< TextureId when it is loading. it causes Load Textures to be queued.
index 6dac0e7..60c0579 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -19,8 +19,8 @@
 #include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <memory>
@@ -344,7 +344,24 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const
   map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay));
   map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount));
   map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetCurrentFrameIndex()) : -1);
-  map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() : mImageCache->GetTotalFrameCount()) : -1);
+
+  // This returns -1 until the loading is finished.
+  int32_t frameCount = mFrameCount;
+  if(mImageCache && frameCount == 0)
+  {
+    frameCount = mImageCache->GetTotalFrameCount();
+
+    if(frameCount <= SINGLE_IMAGE_COUNT && mAnimatedImageLoading && mAnimatedImageLoading.HasLoadingSucceeded())
+    {
+      frameCount = mAnimatedImageLoading.GetImageCount();
+    }
+    else
+    {
+      frameCount = -1;
+    }
+  }
+
+  map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast<int>(frameCount));
 
   map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
 
@@ -766,11 +783,12 @@ void AnimatedImageVisual::DoSetOnScene(Actor& actor)
   mPlacementActor  = actor;
   PrepareTextureSet();
 
-  DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
+  actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged);
 
   Window window = DevelWindow::Get(actor);
   if(window)
   {
+    mPlacementWindow = window;
     DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedImageVisual::OnWindowVisibilityChanged);
   }
 }
@@ -800,12 +818,13 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor)
   mCurrentFrameIndex = FIRST_FRAME_INDEX;
   mCurrentLoopIndex  = FIRST_LOOP;
 
-  DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
+  actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged);
 
-  Window window = DevelWindow::Get(actor);
+  Window window = mPlacementWindow.GetHandle();
   if(window)
   {
     DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedImageVisual::OnWindowVisibilityChanged);
+    mPlacementWindow.Reset();
   }
 }
 
@@ -1115,13 +1134,13 @@ void AnimatedImageVisual::CheckMaskTexture()
   }
 }
 
-void AnimatedImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
+void AnimatedImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible)
 {
   if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP)
   {
     mActionStatus = DevelAnimatedImageVisual::Action::STOP;
     DisplayNextFrame();
-    DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
+    DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this);
   }
 }
 
index b37d74b..d8c2f8e 100644 (file)
@@ -259,9 +259,9 @@ private:
   void CheckMaskTexture();
 
   /**
-   * @brief Callback when the visibility of the actor is changed.
+   * @brief Callback when the inherited visibility of the actor is changed.
    */
-  void OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type);
+  void OnControlInheritedVisibilityChanged(Actor actor, bool visible);
 
   /**
    * @brief Callback when the visibility of the window is changed.
@@ -276,6 +276,7 @@ private:
 
 private:
   Timer                     mFrameDelayTimer;
+  WeakHandle<Window>        mPlacementWindow;
   WeakHandle<Actor>         mPlacementActor;
   ImageVisualShaderFactory& mImageVisualShaderFactory;
 
index adf8da8..e751f90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -21,6 +21,7 @@
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
 
 // EXTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
 
 namespace Dali
@@ -146,12 +147,6 @@ void FixedImageCache::LoadBatch()
 TextureSet FixedImageCache::GetTextureSet(uint32_t frameIndex) const
 {
   TextureSet textureSet = mTextureManager.GetTextureSet(mImageUrls[frameIndex].mTextureId);
-  if(textureSet)
-  {
-    Sampler sampler = Sampler::New();
-    sampler.SetWrapMode(Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT);
-    textureSet.SetSampler(0u, sampler);
-  }
   return textureSet;
 }
 
@@ -165,7 +160,7 @@ void FixedImageCache::MakeReady(bool wasReady, uint32_t frameIndex, bool preMult
 
 void FixedImageCache::ClearCache()
 {
-  if(mTextureManagerAlive)
+  if(Dali::Adaptor::IsAvailable())
   {
     for(std::size_t i = 0; i < mImageUrls.size(); ++i)
     {
@@ -185,7 +180,7 @@ void FixedImageCache::LoadComplete(bool loadSuccess, TextureInformation textureI
 {
   if(loadSuccess)
   {
-    mLoadState           = TextureManager::LoadState::LOAD_FINISHED;
+    mLoadState               = TextureManager::LoadState::LOAD_FINISHED;
     bool isCurrentFrameReady = IsFrameReady(mCurrentFrameIndex);
     if(!mRequestingLoad)
     {
index 2fda611..ece9014 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -42,23 +42,12 @@ ImageCache::ImageCache(TextureManager&                     textureManager,
   mInterval(interval),
   mLoadState(TextureManager::LoadState::NOT_STARTED),
   mRequestingLoad(false),
-  mPreMultiplyOnLoad(preMultiplyOnLoad),
-  mTextureManagerAlive(true)
+  mPreMultiplyOnLoad(preMultiplyOnLoad)
 {
-  mTextureManager.AddObserver(*this);
 }
 
 ImageCache::~ImageCache()
 {
-  if(mTextureManagerAlive)
-  {
-    mTextureManager.RemoveObserver(*this);
-  }
-}
-
-void ImageCache::TextureManagerDestroyed()
-{
-  mTextureManagerAlive = false;
 }
 
 void ImageCache::SetInterval(uint32_t interval)
index c40a895..aee80b2 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_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.
@@ -27,7 +27,7 @@ namespace Toolkit
 {
 namespace Internal
 {
-class ImageCache : public TextureManager::LifecycleObserver
+class ImageCache
 {
 public:
   /**
@@ -137,11 +137,6 @@ public:
   virtual void SetInterval(uint32_t interval);
 
 private:
-  /**
-   * @brief Called before the texture manager is destroyed.
-   */
-  void TextureManagerDestroyed() final;
-
   void AllocateMaskData();
 
 protected:
@@ -156,7 +151,6 @@ protected:
   TextureManager::LoadState           mLoadState;
   bool                                mRequestingLoad : 1;
   bool                                mPreMultiplyOnLoad : 1;
-  bool                                mTextureManagerAlive : 1;
 };
 
 } // namespace Internal
index 370a678..3ece4cb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -20,6 +20,7 @@
 // INTERNAL HEADERS
 #include <dali-toolkit/devel-api/image-loader/texture-manager.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
 
 namespace
@@ -118,7 +119,7 @@ TextureSet RollingAnimatedImageCache::Frame(uint32_t frameIndex)
       synchronouslyLoaded = true;
       interval            = mAnimatedImageLoading.GetFrameInterval(mQueue.Back().mFrameNumber);
     }
-    MakeFrameReady(synchronouslyLoaded, textureSet, interval, preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
+    MakeFrameReady(synchronouslyLoaded, textureSet, mAnimatedImageLoading.GetImageCount(), interval, preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
   }
 
   if(popExist || mQueue.IsEmpty() || synchronouslyLoaded)
@@ -220,7 +221,7 @@ TextureSet RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex, b
                                                                    synchronousLoading,
                                                                    this,
                                                                    preMultiplyOnLoading);
-  if(textureSet)
+  if(textureSet && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
   {
     Sampler sampler = Sampler::New();
     sampler.SetWrapMode(mWrapModeU, mWrapModeV);
@@ -274,7 +275,7 @@ TextureSet RollingAnimatedImageCache::GetFrontTextureSet() const
 
   TextureManager::TextureId textureId  = GetCachedTextureId(0);
   TextureSet                textureSet = mTextureManager.GetTextureSet(textureId);
-  if(textureSet)
+  if(textureSet && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
   {
     Sampler sampler = Sampler::New();
     sampler.SetWrapMode(mWrapModeU, mWrapModeV);
@@ -306,7 +307,7 @@ void RollingAnimatedImageCache::PopFrontCache()
 
 void RollingAnimatedImageCache::ClearCache()
 {
-  while(mTextureManagerAlive && !mQueue.IsEmpty())
+  while(Dali::Adaptor::IsAvailable() && !mQueue.IsEmpty())
   {
     PopFrontCache();
   }
@@ -314,7 +315,7 @@ void RollingAnimatedImageCache::ClearCache()
   mLoadState = TextureManager::LoadState::NOT_STARTED;
 }
 
-void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval, bool preMultiplied)
+void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t frameCount, uint32_t interval, bool preMultiplied)
 {
   if(!loadSuccess)
   {
@@ -327,9 +328,9 @@ void RollingAnimatedImageCache::MakeFrameReady(bool loadSuccess, TextureSet text
     mLoadState = TextureManager::LoadState::LOAD_FINISHED;
 
     // Reset size of Queue according to the real frame count.
-    if(mFrameCount != mAnimatedImageLoading.GetImageCount())
+    if(mFrameCount != frameCount)
     {
-      mFrameCount = mAnimatedImageLoading.GetImageCount();
+      mFrameCount = frameCount;
       mTextureIds.resize(mFrameCount);
       mIntervals.assign(mFrameCount, 0u);
     }
@@ -353,14 +354,14 @@ void RollingAnimatedImageCache::LoadComplete(bool loadSuccess, TextureInformatio
   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::LoadComplete(textureId:%d) start\n", textureInformation.textureId);
   LOG_CACHE;
 
-  if(textureInformation.textureSet)
+  if(textureInformation.textureSet && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
   {
     Sampler sampler = Sampler::New();
     sampler.SetWrapMode(mWrapModeU, mWrapModeV);
     textureInformation.textureSet.SetSampler(0u, sampler);
   }
 
-  MakeFrameReady(loadSuccess, textureInformation.textureSet, textureInformation.interval, textureInformation.preMultiplied);
+  MakeFrameReady(loadSuccess, textureInformation.textureSet, textureInformation.frameCount, textureInformation.interval, textureInformation.preMultiplied);
 
   // TODO : We need to remove some below logics, since user can remove Visual during ResourceReady callback.
 
index 5c63db5..dde53b8 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_ROLLING_ANIMATED_IMAGE_CACHE_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.
@@ -169,10 +169,11 @@ private:
    *
    * @param[in] loadSuccess whether the loading is succeded or not.
    * @param[in] textureSet textureSet for this frame.
+   * @param[in] frameCount Total frame count for this image.
    * @param[in] interval interval between this frame and next frame.
    * @param[in] preMultiplied whether the texture is premultied alpha or not.
    */
-  void MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t interval, bool preMultiplied);
+  void MakeFrameReady(bool loadSuccess, TextureSet textureSet, uint32_t frameCount, uint32_t interval, bool preMultiplied);
 
   /**
    * @brief Pop front entity of Cache.
index 0bb1629..d818417 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
 
 // INTERNAL HEADERS
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
-#include <dali/integration-api/debug.h>
 
 // EXTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
 
 namespace
 {
@@ -220,7 +221,7 @@ void RollingImageCache::PopFrontCache()
 
 void RollingImageCache::ClearCache()
 {
-  while(mTextureManagerAlive && !mQueue.IsEmpty())
+  while(Dali::Adaptor::IsAvailable() && !mQueue.IsEmpty())
   {
     PopFrontCache();
   }
@@ -257,12 +258,6 @@ void RollingImageCache::LoadComplete(bool loadSuccess, TextureInformation textur
 
     if(!frontFrameReady && IsFrontReady())
     {
-      if(textureInformation.textureSet)
-      {
-        Sampler sampler = Sampler::New();
-        sampler.SetWrapMode(Dali::WrapMode::Type::DEFAULT, Dali::WrapMode::Type::DEFAULT);
-        textureInformation.textureSet.SetSampler(0u, sampler);
-      }
       mObserver.FrameReady(textureInformation.textureSet, mInterval, textureInformation.preMultiplied);
     }
   }
index 9c81c3b..9fc2fda 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>
@@ -100,10 +101,10 @@ AnimatedVectorImageVisual::AnimatedVectorImageVisual(VisualFactoryCache& factory
   mLastSentPlayStateId(0u),
   mLoadFailed(false),
   mRendererAdded(false),
-  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;
@@ -114,7 +115,7 @@ AnimatedVectorImageVisual::AnimatedVectorImageVisual(VisualFactoryCache& factory
 
 AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
 {
-  if(!mCoreShutdown)
+  if(Dali::Adaptor::IsAvailable())
   {
     if(mImageUrl.IsBufferResource())
     {
@@ -122,9 +123,6 @@ AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
       textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
     }
 
-    auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
-    vectorAnimationManager.RemoveObserver(*this);
-
     if(mEventCallback)
     {
       mFactoryCache.GetVectorAnimationManager().UnregisterEventCallback(mEventCallback);
@@ -137,12 +135,6 @@ AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
   }
 }
 
-void AnimatedVectorImageVisual::VectorAnimationManagerDestroyed()
-{
-  // Core is shutting down. Don't talk to the plugin any more.
-  mCoreShutdown = true;
-}
-
 void AnimatedVectorImageVisual::GetNaturalSize(Vector2& naturalSize)
 {
   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
@@ -221,6 +213,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 +278,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 +401,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;
+    }
   }
 }
 
@@ -428,9 +441,6 @@ void AnimatedVectorImageVisual::OnInitialize(void)
   mVectorAnimationTask->KeepRasterizedBuffer(mEnableFrameCache);
   mVectorAnimationTask->RequestLoad(mImageUrl, encodedImageBuffer, IsSynchronousLoadingRequired());
 
-  auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
-  vectorAnimationManager.AddObserver(*this);
-
   Shader shader = GenerateShader();
 
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
@@ -471,11 +481,12 @@ void AnimatedVectorImageVisual::DoSetOnScene(Actor& actor)
     mSizeNotification = actor.AddPropertyNotification(Actor::Property::SIZE, StepCondition(3.0f));
     mSizeNotification.NotifySignal().Connect(this, &AnimatedVectorImageVisual::OnSizeNotification);
 
-    DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedVectorImageVisual::OnControlVisibilityChanged);
+    actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged);
 
     Window window = DevelWindow::Get(actor);
     if(window)
     {
+      mPlacementWindow = window;
       DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged);
     }
 
@@ -507,12 +518,13 @@ void AnimatedVectorImageVisual::DoSetOffScene(Actor& actor)
   actor.RemovePropertyNotification(mScaleNotification);
   actor.RemovePropertyNotification(mSizeNotification);
 
-  DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedVectorImageVisual::OnControlVisibilityChanged);
+  actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged);
 
-  Window window = DevelWindow::Get(actor);
+  Window window = mPlacementWindow.GetHandle();
   if(window)
   {
     DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged);
+    mPlacementWindow.Reset();
   }
 
   mPlacementActor.Reset();
@@ -605,7 +617,7 @@ void AnimatedVectorImageVisual::OnDoAction(const Property::Index actionId, const
     }
     case DevelAnimatedVectorImageVisual::Action::FLUSH:
     {
-      if(DALI_LIKELY(!mCoreShutdown))
+      if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
       {
         SendAnimationData();
       }
@@ -718,7 +730,7 @@ void AnimatedVectorImageVisual::OnAnimationFinished(uint32_t playStateId)
     }
   }
 
-  if(mImpl->mRenderer)
+  if(!mNotifyAfterRasterization && mImpl->mRenderer)
   {
     mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
   }
@@ -737,14 +749,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);
       }
     }
@@ -788,7 +804,7 @@ void AnimatedVectorImageVisual::StopAnimation()
 
 void AnimatedVectorImageVisual::TriggerVectorRasterization()
 {
-  if(!mEventCallback && !mCoreShutdown)
+  if(!mEventCallback && Dali::Adaptor::IsAvailable())
   {
     mEventCallback               = MakeCallback(this, &AnimatedVectorImageVisual::OnProcessEvents);
     auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
@@ -841,14 +857,14 @@ void AnimatedVectorImageVisual::OnSizeNotification(PropertyNotification& source)
   }
 }
 
-void AnimatedVectorImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
+void AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible)
 {
   if(!visible)
   {
     StopAnimation();
     TriggerVectorRasterization();
 
-    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
+    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this);
   }
 }
 
index fc7d7a4..fe3396a 100644 (file)
@@ -53,7 +53,7 @@ using AnimatedVectorImageVisualPtr = IntrusivePtr<AnimatedVectorImageVisual>;
  * | url                      | STRING           |
  *
  */
-class AnimatedVectorImageVisual : public Visual::Base, public ConnectionTracker, public VectorAnimationManager::LifecycleObserver
+class AnimatedVectorImageVisual : public Visual::Base, public ConnectionTracker
 {
 public:
   /**
@@ -99,12 +99,6 @@ public: // from Visual
    */
   void EnablePreMultipliedAlpha(bool preMultiplied) override;
 
-protected: // From VectorAnimationManager::LifecycleObserver:
-  /**
-   * @copydoc VectorAnimationManager::LifecycleObserver::VectorAnimationManagerDestroyed()
-   */
-  void VectorAnimationManagerDestroyed() override;
-
 protected:
   /**
    * @brief Constructor.
@@ -220,7 +214,7 @@ private:
   /**
    * @brief Callback when the visibility of the actor is changed.
    */
-  void OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type);
+  void OnControlInheritedVisibilityChanged(Actor actor, bool visible);
 
   /**
    * @brief Callback when the visibility of the window is changed.
@@ -239,6 +233,7 @@ private:
   AnimatedVectorImageVisual& operator=(const AnimatedVectorImageVisual& visual) = delete;
 
 private:
+  WeakHandle<Window>                 mPlacementWindow;
   VisualUrl                          mImageUrl;
   VectorAnimationTask::AnimationData mAnimationData;
   VectorAnimationTaskPtr             mVectorAnimationTask;
@@ -256,10 +251,10 @@ private:
 
   bool mLoadFailed : 1;
   bool mRendererAdded : 1;
-  bool mCoreShutdown : 1;
   bool mRedrawInScalingDown : 1;
   bool mEnableFrameCache : 1;
   bool mUseNativeImage : 1;
+  bool mNotifyAfterRasterization : 1;
 };
 
 } // namespace Internal
index fda5168..2d1fce9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -44,7 +44,6 @@ DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_IMAGE_PERFORMANCE_MARKER, false)
 
 VectorAnimationManager::VectorAnimationManager()
 : mEventCallbacks(),
-  mLifecycleObservers(),
   mVectorAnimationThread(nullptr),
   mProcessorRegistered(false)
 {
@@ -52,32 +51,12 @@ VectorAnimationManager::VectorAnimationManager()
 
 VectorAnimationManager::~VectorAnimationManager()
 {
-  mEventCallbacks.clear();
+  mEventCallbacks.Clear();
 
   if(mProcessorRegistered && Adaptor::IsAvailable())
   {
     Adaptor::Get().UnregisterProcessor(*this, true);
   }
-
-  for(auto observer : mLifecycleObservers)
-  {
-    observer->VectorAnimationManagerDestroyed();
-  }
-}
-
-void VectorAnimationManager::AddObserver(VectorAnimationManager::LifecycleObserver& observer)
-{
-  DALI_ASSERT_DEBUG(mLifecycleObservers.end() == std::find(mLifecycleObservers.begin(), mLifecycleObservers.end(), &observer));
-  mLifecycleObservers.push_back(&observer);
-}
-
-void VectorAnimationManager::RemoveObserver(VectorAnimationManager::LifecycleObserver& observer)
-{
-  auto iterator = std::find(mLifecycleObservers.begin(), mLifecycleObservers.end(), &observer);
-  if(iterator != mLifecycleObservers.end())
-  {
-    mLifecycleObservers.erase(iterator);
-  }
 }
 
 VectorAnimationThread& VectorAnimationManager::GetVectorAnimationThread()
@@ -92,7 +71,7 @@ VectorAnimationThread& VectorAnimationManager::GetVectorAnimationThread()
 
 void VectorAnimationManager::RegisterEventCallback(CallbackBase* callback)
 {
-  mEventCallbacks.emplace_back(std::unique_ptr<Dali::CallbackBase>(callback));
+  mEventCallbacks.PushBack(callback); ///< Take ownership of callback.
 
   if(!mProcessorRegistered)
   {
@@ -103,16 +82,12 @@ void VectorAnimationManager::RegisterEventCallback(CallbackBase* callback)
 
 void VectorAnimationManager::UnregisterEventCallback(CallbackBase* callback)
 {
-  auto iter = std::find_if(mEventCallbacks.begin(),
-                           mEventCallbacks.end(),
-                           [callback](const std::unique_ptr<CallbackBase>& element) {
-                             return element.get() == callback;
-                           });
-  if(iter != mEventCallbacks.end())
+  auto iter = mEventCallbacks.Find(callback);
+  if(iter != mEventCallbacks.End())
   {
-    mEventCallbacks.erase(iter);
+    mEventCallbacks.Erase(iter);
 
-    if(mEventCallbacks.empty())
+    if(mEventCallbacks.Count() == 0u)
     {
       if(Adaptor::IsAvailable())
       {
@@ -128,10 +103,10 @@ void VectorAnimationManager::Process(bool postProcessor)
 #ifdef TRACE_ENABLED
   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
   {
-    if(mEventCallbacks.size() > 0u)
+    if(mEventCallbacks.Count() > 0u)
     {
       std::ostringstream oss;
-      oss << "[" << mEventCallbacks.size() << "]";
+      oss << "[" << mEventCallbacks.Count() << "]";
       DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_VECTOR_ANIMATION_MANAGER_PROCESS", oss.str().c_str());
     }
   }
@@ -145,15 +120,15 @@ void VectorAnimationManager::Process(bool postProcessor)
 #ifdef TRACE_ENABLED
   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
   {
-    if(mEventCallbacks.size() > 0u)
+    if(mEventCallbacks.Count() > 0u)
     {
       std::ostringstream oss;
-      oss << "[" << mEventCallbacks.size() << "]";
+      oss << "[" << mEventCallbacks.Count() << "]";
       DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_VECTOR_ANIMATION_MANAGER_PROCESS", oss.str().c_str());
     }
   }
 #endif
-  mEventCallbacks.clear();
+  mEventCallbacks.Clear();
 
   Adaptor::Get().UnregisterProcessor(*this, true);
   mProcessorRegistered = false;
index c3cba21..53dbb06 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_VECTOR_ANIMATION_MANAGER_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.
@@ -19,6 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/integration-api/ordered-set.h>
 #include <dali/integration-api/processor-interface.h>
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/signals/callback.h>
@@ -40,11 +41,6 @@ class VectorAnimationThread;
 class VectorAnimationManager : public Integration::Processor
 {
 public:
-  struct LifecycleObserver
-  {
-    virtual void VectorAnimationManagerDestroyed() = 0;
-  };
-
   /**
    * @brief Constructor.
    */
@@ -56,18 +52,6 @@ public:
   ~VectorAnimationManager() override;
 
   /**
-   * Add a lifecycle observer
-   * @param[in] observer The object watching this one
-   */
-  void AddObserver(LifecycleObserver& observer);
-
-  /**
-   * Remove a lifecycle observer
-   * @param[in] observer The object watching this one
-   */
-  void RemoveObserver(LifecycleObserver& observer);
-
-  /**
    * Get the vector animation thread.
    * @return A raw pointer pointing to the vector animation thread.
    */
@@ -110,10 +94,10 @@ private:
   VectorAnimationManager& operator=(const VectorAnimationManager& manager) = delete;
 
 private:
-  std::vector<std::unique_ptr<CallbackBase>> mEventCallbacks;
-  std::vector<LifecycleObserver*>            mLifecycleObservers;
-  std::unique_ptr<VectorAnimationThread>     mVectorAnimationThread;
-  bool                                       mProcessorRegistered;
+  Dali::Integration::OrderedSet<CallbackBase> mEventCallbacks; ///< Event triggered callback lists (owned)
+
+  std::unique_ptr<VectorAnimationThread> mVectorAnimationThread;
+  bool                                   mProcessorRegistered : 1;
 };
 
 } // namespace Internal
index 4f4e97d..ac448c0 100644 (file)
@@ -98,6 +98,7 @@ VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
   mForward(true),
   mUpdateFrameNumber(false),
   mNeedAnimationFinishedTrigger(true),
+  mNeedForceRenderOnceTrigger(false),
   mAnimationDataUpdated(false),
   mDestroyTask(false),
   mLoadRequest(false),
@@ -107,6 +108,7 @@ VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
   mLayerInfoCached(false),
   mMarkerInfoCached(false),
   mEnableFrameCache(false),
+  mNotifyAfterRasterization(false),
   mSizeUpdated(false)
 {
   mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted);
@@ -376,6 +378,9 @@ void VectorAnimationTask::PauseAnimation()
   {
     mPlayState = PlayState::PAUSED;
 
+    // Ensure to render paused frame.
+    mNeedForceRenderOnceTrigger = true;
+
     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this);
   }
 }
@@ -467,10 +472,22 @@ void VectorAnimationTask::SetPlayRange(const Property::Array& playRange)
     if(mStartFrame > mCurrentFrame)
     {
       mCurrentFrame = mStartFrame;
+
+      if(mPlayState != PlayState::PLAYING)
+      {
+        // Ensure to render current frame.
+        mNeedForceRenderOnceTrigger = true;
+      }
     }
     else if(mEndFrame < mCurrentFrame)
     {
       mCurrentFrame = mEndFrame;
+
+      if(mPlayState != PlayState::PLAYING)
+      {
+        // Ensure to render current frame.
+        mNeedForceRenderOnceTrigger = true;
+      }
     }
 
     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mImageUrl.GetUrl().c_str(), this);
@@ -496,6 +513,12 @@ void VectorAnimationTask::SetCurrentFrameNumber(uint32_t frameNumber)
     mCurrentFrame      = frameNumber;
     mUpdateFrameNumber = false;
 
+    if(mPlayState != PlayState::PLAYING)
+    {
+      // Ensure to render current frame.
+      mNeedForceRenderOnceTrigger = true;
+    }
+
     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this);
   }
   else
@@ -693,6 +716,8 @@ bool VectorAnimationTask::Rasterize()
     mForward     = true;
     mCurrentLoop = 0;
 
+    mNeedForceRenderOnceTrigger = true;
+
     if(mVectorRenderer)
     {
       // Notify the Renderer that rendering is stopped.
@@ -711,6 +736,14 @@ bool VectorAnimationTask::Rasterize()
     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this);
   }
 
+  // Forcely trigger render once if need.
+  if(mNotifyAfterRasterization || mNeedForceRenderOnceTrigger)
+  {
+    Mutex::ScopedLock lock(mMutex);
+    mVectorAnimationThread.RequestForceRenderOnce();
+    mNeedForceRenderOnceTrigger = false;
+  }
+
   if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED)
   {
     mKeepAnimation = true;
@@ -845,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 eb48a13..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;
   };
 
   /**
@@ -257,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()
@@ -276,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.
@@ -416,6 +420,7 @@ private:
   bool                                 mForward : 1;
   bool                                 mUpdateFrameNumber : 1;
   bool                                 mNeedAnimationFinishedTrigger : 1;
+  bool                                 mNeedForceRenderOnceTrigger : 1;
   bool                                 mAnimationDataUpdated : 1;
   bool                                 mDestroyTask : 1;
   bool                                 mLoadRequest : 1;
@@ -425,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 1aa9bd8..066d506 100644 (file)
@@ -258,10 +258,13 @@ void GradientVisual::OnInitialize()
   TextureSet    textureSet    = TextureSet::New();
   Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
   textureSet.SetTexture(0u, lookupTexture);
-  Dali::WrapMode::Type wrap    = GetWrapMode(mGradient->GetSpreadMethod());
-  Sampler              sampler = Sampler::New();
-  sampler.SetWrapMode(wrap, wrap);
-  textureSet.SetSampler(0u, sampler);
+  Dali::WrapMode::Type wrap = GetWrapMode(mGradient->GetSpreadMethod());
+  if(wrap != Dali::WrapMode::DEFAULT)
+  {
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(wrap, wrap);
+    textureSet.SetSampler(0u, sampler);
+  }
 
   mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
index 6b30a02..02d08af 100644 (file)
@@ -694,7 +694,7 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te
     }
 
     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
-    if(!atlasing)
+    if(!atlasing && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
     {
       Sampler sampler = Sampler::New();
       sampler.SetWrapMode(mWrapModeU, mWrapModeV);
@@ -744,7 +744,9 @@ void ImageVisual::InitializeRenderer()
     else
     {
       mTextures = mFactoryCache.GetTextureManager().GetTextureSet(mTextureId);
-      if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) && mTextures)
+      if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) &&
+         mTextures &&
+         (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
       {
         Sampler sampler = Sampler::New();
         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
@@ -1057,9 +1059,12 @@ void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureIn
     }
     else
     {
-      Sampler sampler = Sampler::New();
-      sampler.SetWrapMode(mWrapModeU, mWrapModeV);
-      textureInformation.textureSet.SetSampler(0u, sampler);
+      if(mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT)
+      {
+        Sampler sampler = Sampler::New();
+        sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+        textureInformation.textureSet.SetSampler(0u, sampler);
+      }
 
       mImpl->mRenderer.SetTextures(textureInformation.textureSet);
       ComputeTextureSize();
index 2544899..1047eaf 100644 (file)
@@ -105,13 +105,6 @@ void NPatchVisual::LoadImages()
     // Load the auxiliary image
     mAuxiliaryTextureSet = textureManager.LoadTexture(mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, maskingDataPtr, synchronousLoading, mAuxiliaryTextureId, atlasRect, atlasRectSize, atlasing, loadingStatus, this, nullptr, imageAtlasManagerPtr, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad);
 
-    if(mAuxiliaryTextureSet)
-    {
-      Sampler sampler = Sampler::New();
-      sampler.SetWrapMode(WrapMode::DEFAULT, WrapMode::DEFAULT);
-      mAuxiliaryTextureSet.SetSampler(0u, sampler);
-    }
-
     // If synchronousLoading is true, we can check the auxiliaryResource's status now.
     if(synchronousLoading)
     {
@@ -613,14 +606,7 @@ void NPatchVisual::LoadComplete(bool loadSuccess, TextureInformation textureInfo
     }
     if(loadSuccess)
     {
-      mAuxiliaryTextureSet = textureInformation.textureSet;
-      if(mAuxiliaryTextureSet)
-      {
-        Sampler sampler = Sampler::New();
-        sampler.SetWrapMode(WrapMode::DEFAULT, WrapMode::DEFAULT);
-        mAuxiliaryTextureSet.SetSampler(0u, sampler);
-      }
-
+      mAuxiliaryTextureSet     = textureInformation.textureSet;
       mAuxiliaryResourceStatus = Toolkit::Visual::ResourceStatus::READY;
     }
     else
index 33e2c41..5d2de15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -53,7 +53,7 @@ namespace
 {
 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false);
 
-const int CUSTOM_PROPERTY_COUNT(2); // uTextColorAnimatable, uHasMultipleTextColors
+const int CUSTOM_PROPERTY_COUNT(3); // uTextColorAnimatable, uHasMultipleTextColors, requireRender
 
 /**
  * Return Property index for the given string key
@@ -137,7 +137,7 @@ void TextColorConstraint(Vector4& current, const PropertyInputContainer& inputs)
 void OpacityConstraint(float& current, const PropertyInputContainer& inputs)
 {
   // Make zero if the alpha value of text color is zero to skip rendering text
-  if(EqualsZero(inputs[0]->GetVector4().a))
+  if(EqualsZero(inputs[0]->GetVector4().a) && !inputs[1]->GetBoolean())
   {
     current = 0.0f;
   }
@@ -259,7 +259,9 @@ TextVisual::TextVisual(VisualFactoryCache& factoryCache, TextVisualShaderFactory
   mHasMultipleTextColorsIndex(Property::INVALID_INDEX),
   mAnimatableTextColorPropertyIndex(Property::INVALID_INDEX),
   mTextColorAnimatableIndex(Property::INVALID_INDEX),
-  mRendererUpdateNeeded(false)
+  mTextRequireRenderPropertyIndex(Property::INVALID_INDEX),
+  mRendererUpdateNeeded(false),
+  mTextRequireRender(false)
 {
   // Enable the pre-multiplied alpha to improve the text quality
   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
@@ -276,6 +278,7 @@ void TextVisual::OnInitialize()
 
   mImpl->mRenderer = VisualRenderer::New(geometry, shader);
   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
+  mTextRequireRenderPropertyIndex = mImpl->mRenderer.RegisterUniqueProperty("requireRender", mTextRequireRender);
   mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", static_cast<float>(false));
 }
 
@@ -340,6 +343,7 @@ void TextVisual::DoSetOnScene(Actor& actor)
       // VisualRenderer::Property::OPACITY uses same animatable property internally.
       mOpacityConstraint = Constraint::New<float>(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
       mOpacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+      mOpacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex));
     }
     mOpacityConstraint.Apply();
   }
@@ -350,12 +354,13 @@ void TextVisual::DoSetOnScene(Actor& actor)
   UpdateRenderer();
 }
 
-void TextVisual::RemoveRenderer(Actor& actor)
+void TextVisual::RemoveRenderer(Actor& actor, bool removeDefaultRenderer)
 {
   for(RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter)
   {
     Renderer renderer = (*iter);
-    if(renderer)
+    if(renderer &&
+       (removeDefaultRenderer || (renderer != mImpl->mRenderer)))
     {
       // Removes the renderer from the actor.
       actor.RemoveRenderer(renderer);
@@ -376,7 +381,7 @@ void TextVisual::DoSetOffScene(Actor& actor)
     mOpacityConstraint.Remove();
   }
 
-  RemoveRenderer(actor);
+  RemoveRenderer(actor, true);
 
   // Resets the control handle.
   mControl.Reset();
@@ -502,16 +507,19 @@ void TextVisual::UpdateRenderer()
   const bool isWidthRelative  = fabsf(mImpl->mTransform.mOffsetSizeMode.z) < Math::MACHINE_EPSILON_1000;
   const bool isHeightRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.w) < Math::MACHINE_EPSILON_1000;
 
+  const float controlWidth = mImpl->mControlSize.width;
+  const float controlHeight = mImpl->mControlSize.height;
+
   // Round the size and offset to avoid pixel alignement issues.
-  relayoutSize.width  = floorf(0.5f + (isWidthRelative ? mImpl->mControlSize.width * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width));
-  relayoutSize.height = floorf(0.5f + (isHeightRelative ? mImpl->mControlSize.height * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height));
+  relayoutSize.width  = floorf(0.5f + (isWidthRelative ? controlWidth * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width));
+  relayoutSize.height = floorf(0.5f + (isHeightRelative ? controlHeight * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height));
 
   auto textLengthUtf32 = mController->GetNumberOfCharacters();
 
   if((fabsf(relayoutSize.width) < Math::MACHINE_EPSILON_1000) || (fabsf(relayoutSize.height) < Math::MACHINE_EPSILON_1000) || textLengthUtf32 == 0u)
   {
     // Remove the texture set and any renderer previously set.
-    RemoveRenderer(control);
+    RemoveRenderer(control, true);
 
     // Nothing else to do if the relayout size is zero.
     ResourceReady(Toolkit::Visual::ResourceStatus::READY);
@@ -527,7 +535,8 @@ void TextVisual::UpdateRenderer()
     mRendererUpdateNeeded = false;
 
     // Remove the texture set and any renderer previously set.
-    RemoveRenderer(control);
+    // Note, we don't need to remove the mImpl->Renderer, since it will be added again after AddRenderer call.
+    RemoveRenderer(control, false);
 
     if((relayoutSize.width > Math::MACHINE_EPSILON_1000) &&
        (relayoutSize.height > Math::MACHINE_EPSILON_1000))
@@ -564,16 +573,29 @@ void TextVisual::UpdateRenderer()
         shadowEnabled = true;
       }
 
-      const bool outlineEnabled             = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
-      const bool backgroundEnabled          = mController->GetTextModel()->IsBackgroundEnabled();
-      const bool markupOrSpannedText        = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced();
-      const bool markupUnderlineEnabled     = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet();
-      const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet();
-      const bool underlineEnabled           = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
-      const bool strikethroughEnabled       = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
-      const bool backgroundMarkupSet        = mController->GetTextModel()->IsMarkupBackgroundColorSet();
-      const bool styleEnabled               = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet);
-      const bool isOverlayStyle             = underlineEnabled || strikethroughEnabled;
+      const bool outlineEnabled               = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
+      const bool backgroundEnabled            = mController->GetTextModel()->IsBackgroundEnabled();
+      const bool markupOrSpannedText          = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced();
+      const bool markupUnderlineEnabled       = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet();
+      const bool markupStrikethroughEnabled   = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet();
+      const bool underlineEnabled             = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled;
+      const bool strikethroughEnabled         = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled;
+      const bool backgroundMarkupSet          = mController->GetTextModel()->IsMarkupBackgroundColorSet();
+      const bool cutoutEnabled                = mController->IsTextCutout();
+      const bool backgroundWithCutoutEnabled  = mController->GetTextModel()->IsBackgroundWithCutoutEnabled();
+      const bool styleEnabled                 = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet || cutoutEnabled || backgroundWithCutoutEnabled);
+      const bool isOverlayStyle               = underlineEnabled || strikethroughEnabled;
+
+      // if background with cutout is enabled, This text visual must render the entire control size.
+
+      if(cutoutEnabled)
+      {
+        relayoutSize = Vector2(controlWidth, controlHeight);
+        mImpl->mTransform.mSize.width = controlWidth;
+        mImpl->mTransform.mSize.height = controlHeight;
+        mImpl->mTransform.mOffset.x = 0;
+        mImpl->mTransform.mOffset.y = 0;
+      }
 
       AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle);
 
@@ -765,6 +787,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
     Renderer renderer = (*iter);
     if(renderer)
     {
+      // Note, AddRenderer will ignore renderer if it is already added. @SINCE 2_3.22
       actor.AddRenderer(renderer);
 
       if(renderer != mImpl->mRenderer)
@@ -787,6 +810,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
           // VisualRenderer::Property::OPACITY uses same animatable property internally.
           Constraint opacityConstraint = Constraint::New<float>(renderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint);
           opacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex));
+          opacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex));
           opacityConstraint.Apply();
         }
       }
@@ -796,6 +820,8 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple
 
 TextureSet TextVisual::GetTextTexture(const Vector2& size)
 {
+  const bool cutoutEnabled = mController->IsTextCutout();
+
   // Filter mode needs to be set to linear to produce better quality while scaling.
   Sampler sampler = Sampler::New();
   sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR);
@@ -803,22 +829,48 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size)
   TextureSet textureSet = TextureSet::New();
 
   // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
-  Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor()) ? Pixel::RGBA8888 : Pixel::L8;
+  Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor() || cutoutEnabled) ? Pixel::RGBA8888 : Pixel::L8;
 
   // Check the text direction
   Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
-
+  uint32_t textureSetIndex = 0u;
   // Create a texture for the text without any styles
-  PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
 
-  uint32_t textureSetIndex = 0u;
-  AddTexture(textureSet, data, sampler, textureSetIndex);
-  ++textureSetIndex;
+  Devel::PixelBuffer cutoutData;
+  float cutoutAlpha = mController->GetTextModel()->GetDefaultColor().a;
+  if(cutoutEnabled)
+  {
+    cutoutData = mTypesetter->RenderWithPixelBuffer(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
+
+    // Make transparent buffer.
+    // If the cutout is enabled, a separate texture is not used for the text.
+    Devel::PixelBuffer buffer = mTypesetter->CreateFullBackgroundBuffer(1, 1, Vector4(0.f, 0.f ,0.f ,0.f));
+    PixelData data = Devel::PixelBuffer::Convert(buffer);
+    AddTexture(textureSet, data, sampler, textureSetIndex);
+    ++textureSetIndex;
+  }
+  else
+  {
+    PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
+    AddTexture(textureSet, data, sampler, textureSetIndex);
+    ++textureSetIndex;
+  }
+
 
   if(mTextShaderFeatureCache.IsEnabledStyle())
   {
     // Create RGBA texture for all the text styles that render in the background (without the text itself)
-    PixelData styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+    PixelData styleData;
+
+    if(cutoutEnabled && cutoutData)
+    {
+      styleData = mTypesetter->RenderWithCutout(size, textDirection, cutoutData, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888, cutoutAlpha);
+    }
+    else
+    {
+      styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+    }
+
     AddTexture(textureSet, styleData, sampler, textureSetIndex);
     ++textureSetIndex;
   }
@@ -851,6 +903,15 @@ Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, const TextVis
   return shader;
 }
 
+void TextVisual::SetRequireRender(bool requireRender)
+{
+  mTextRequireRender = requireRender;
+  if(mImpl->mRenderer)
+  {
+    mImpl->mRenderer.SetProperty(mTextRequireRenderPropertyIndex, mTextRequireRender);
+  }
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 7be059c..0d5e5f8 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_VISUAL_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.
@@ -116,6 +116,16 @@ public:
   };
 
   /**
+   * @brief Set the text to be always rendered
+   * @param[in] visual The text visual.
+   * @param[in] requireRender Whether to text always rendered.
+   */
+  static void SetRequireRender(Toolkit::Visual::Base visual, bool requireRender)
+  {
+    GetVisualObject(visual).SetRequireRender(requireRender);
+  };
+
+  /**
    * @brief Instantly updates the renderer
    * @param[in] visual The text visual.
    */
@@ -239,7 +249,7 @@ private:
   /**
    * @brief Removes the text's renderer.
    */
-  void RemoveRenderer(Actor& actor);
+  void RemoveRenderer(Actor& actor, bool removeDefaultRenderer);
 
   /**
    * @brief Create a texture in textureSet and add it.
@@ -293,6 +303,12 @@ private:
   Shader GetTextShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder);
 
   /**
+   * @brief Set the text to be always rendered
+   * @param[in] requireRender Whether to text always rendered.
+   */
+  void SetRequireRender(bool requireRender);
+
+  /**
    * @brief Retrieve the TextVisual object.
    * @param[in] visual A handle to the TextVisual
    * @return The TextVisual object
@@ -318,7 +334,9 @@ private:
   Property::Index   mHasMultipleTextColorsIndex;       ///< The index of uHasMultipleTextColors proeprty.
   Property::Index   mAnimatableTextColorPropertyIndex; ///< The index of animatable text color property registered by the control.
   Property::Index   mTextColorAnimatableIndex;         ///< The index of uTextColorAnimatable property.
+  Property::Index   mTextRequireRenderPropertyIndex;   ///< The index of requireRender property.
   bool              mRendererUpdateNeeded : 1;         ///< The flag to indicate whether the renderer needs to be updated.
+  bool              mTextRequireRender : 1;            ///< The flag to indicate whether the text needs to be rendered.
   RendererContainer mRendererList;
 };
 
index 43fe953..81a5ec7 100644 (file)
@@ -39,6 +39,7 @@ const char* TOKEN_TIME_PERIOD("timePeriod");
 const char* TOKEN_DURATION("duration");
 const char* TOKEN_DELAY("delay");
 const char* TOKEN_ALPHA_FUNCTION("alphaFunction");
+const char* TOKEN_ANIMATION_TYPE("animationType");
 
 DALI_ENUM_TO_STRING_TABLE_BEGIN(ALPHA_FUNCTION_BUILTIN)
   DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, LINEAR)
@@ -315,6 +316,24 @@ TransitionData::Animator* TransitionData::ConvertMap(const Property::Map& map)
             }
           }
         }
+        else if(key == TOKEN_ANIMATION_TYPE)
+        {
+          if((value.GetType() == Property::STRING))
+          {
+            if(value.Get<std::string>() == "TO")
+            {
+              animator->animationType = AnimationType::TO;
+            }
+            else if(value.Get<std::string>() == "BETWEEN")
+            {
+              animator->animationType = AnimationType::BETWEEN;
+            }
+            else if(value.Get<std::string>() == "BY")
+            {
+              animator->animationType = AnimationType::BY;
+            }
+          }
+        }
       }
     }
   }
index 39c84f9..1274438 100644 (file)
@@ -41,6 +41,13 @@ typedef IntrusivePtr<TransitionData> TransitionDataPtr;
 class TransitionData : public BaseObject
 {
 public:
+    enum class AnimationType : uint8_t
+  {
+    TO,     ///< Animating TO the given value
+    BY,     ///< Animating BY the given value
+    BETWEEN ///< Animating BETWEEN key-frames
+  };
+
   /**
    * @brief TransitionDataElement Describes one animator of an transition.
    */
@@ -51,6 +58,7 @@ public:
       alphaFunction(AlphaFunction::DEFAULT),
       timePeriodDelay(0.0f),
       timePeriodDuration(1.0f),
+      animationType(AnimationType::TO),
       animate(false)
     {
     }
@@ -62,6 +70,7 @@ public:
     Dali::AlphaFunction alphaFunction;
     float               timePeriodDelay;
     float               timePeriodDuration;
+    AnimationType       animationType;
     bool                animate;
   };
 
index b3d8201..aee602d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 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.
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/internal/helpers/property-helper.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
@@ -121,7 +122,7 @@ Internal::Visual::Base::Impl::Impl(FittingMode fittingMode, Toolkit::Visual::Typ
   mMixColor(Color::WHITE),
   mControlSize(Vector2::ZERO),
   mDecorationData(nullptr),
-  mDepthIndex(0.0f),
+  mDepthIndex(Toolkit::DepthIndex::AUTO_INDEX),
   mFittingMode(fittingMode),
   mFlags(0),
   mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
index 3d8e79e..ed6e00c 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali/public-api/rendering/visual-renderer.h>
 
 //INTERNAL HEARDER
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
@@ -519,10 +520,16 @@ void Visual::Base::DoActionExtension(const Dali::Property::Index actionId, const
 
 void Visual::Base::SetDepthIndex(int index)
 {
-  mImpl->mDepthIndex = index;
-  if(mImpl->mRenderer)
+  // Clamp input value as valid range.
+  Dali::ClampInPlace(index, static_cast<int>(Toolkit::DepthIndex::MINIMUM_DEPTH_INDEX), static_cast<int>(Toolkit::DepthIndex::MAXIMUM_DEPTH_INDEX));
+
+  if(mImpl->mDepthIndex != index)
   {
-    mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+    mImpl->mDepthIndex = index;
+    if(mImpl->mRenderer)
+    {
+      mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+    }
   }
 }
 
@@ -542,7 +549,14 @@ void Visual::Base::SetOnScene(Actor& actor)
     if(mImpl->mRenderer)
     {
       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
-      mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+      if(mImpl->mDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
+      {
+        mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, static_cast<int>(DepthIndex::CONTENT));
+      }
+      else
+      {
+        mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
+      }
     }
 
     mImpl->mFlags |= Impl::IS_ON_SCENE;
@@ -1029,7 +1043,10 @@ void Visual::Base::SetupTransition(
       {
         if(animator.initialValue.GetType() != Property::NONE)
         {
-          mImpl->mRenderer.SetProperty(index, initialValue);
+          if(animator.animationType != TransitionData::AnimationType::BETWEEN)
+          {
+            mImpl->mRenderer.SetProperty(index, initialValue);
+          }
         }
 
         if(!transition)
@@ -1037,11 +1054,26 @@ void Visual::Base::SetupTransition(
           transition = Dali::Animation::New(0.1f);
         }
 
-        transition.AnimateTo(Property(mImpl->mRenderer, index),
-                             targetValue,
-                             animator.alphaFunction,
-                             TimePeriod(animator.timePeriodDelay,
-                                        animator.timePeriodDuration));
+        if(animator.animationType == TransitionData::AnimationType::BETWEEN)
+        {
+          Dali::KeyFrames keyFrames = Dali::KeyFrames::New();
+          keyFrames.Add(0.0f, animator.initialValue);
+          keyFrames.Add(1.0f, animator.targetValue);
+          transition.AnimateBetween(Property(mImpl->mRenderer, index),keyFrames, TimePeriod(animator.timePeriodDelay, animator.timePeriodDuration));
+        }
+        else if(animator.animationType == TransitionData::AnimationType::BY)
+        {
+          // To Do
+          DALI_LOG_WARNING("AnimationType::By is not supported yet. \n");
+        }
+        else
+        {
+          transition.AnimateTo(Property(mImpl->mRenderer, index),
+                      targetValue,
+                      animator.alphaFunction,
+                      TimePeriod(animator.timePeriodDelay,
+                                animator.timePeriodDuration));
+        }
       }
     }
   }
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;
index 67b5ab0..40f34a0 100644 (file)
@@ -581,7 +581,7 @@ void Control::OnPropertySet(Property::Index index, const Property::Value& proper
     case Actor::Property::VISIBLE:
     {
       auto* accessible = GetAccessibleObject();
-      if(DALI_LIKELY(accessible))
+      if(DALI_LIKELY(accessible) && accessible->IsHighlighted())
       {
         accessible->EmitVisible(Self().GetProperty<bool>(Actor::Property::VISIBLE));
       }
index 6f52832..a7b986b 100644 (file)
@@ -126,13 +126,22 @@ public:
        * @brief name "enableTransitionEffect", type Boolean
        *
        * This effect is a crossfade effect when the image is replaced.
-       * the default duration of the crossfade effect is 1.5 seconds.
+       * the default duration of the crossfade effect is 0.3 seconds.
        * if the placeholder is enabled, the cross effect applies when the image is changed from a placeholder image to a new image.
        * if not, the cross effect applies when a new image is shown or is changed from the previous image to a new image.
        * @SINCE_2_2.24
        */
       ENABLE_TRANSITION_EFFECT,
 
+      /**
+       * @brief name "transitionEffectOption", type Map
+       *
+       * This option is for transition effect when the image is replaced.
+       * if not, the cross effect use default option.
+       * @SINCE_2_2.24
+       */
+      TRANSITION_EFFECT_OPTION,
+
       // Animatable properties
 
       /**
index 81dc48e..978a3a5 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 18;
+const unsigned int TOOLKIT_MICRO_VERSION = 24;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 16cddcc..b841598 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 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.
@@ -287,6 +287,7 @@ int GenerateShaderSources(fs::path inDir, fs::path outDir, const bool generateBu
   cout << "====================================================================" << endl;
 
   BuiltInFilesGenerator generator(outDir);
+  bool shaderGenerated = false;
 
   for(auto& file : fs::directory_iterator(inDir))
   {
@@ -303,8 +304,19 @@ int GenerateShaderSources(fs::path inDir, fs::path outDir, const bool generateBu
           if(shaderFile.is_open())
           {
             fs::path outFilePath(GetShaderOutputFilePath(outDir, filename));
-            GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath);
             generator.Add(std::move(shaderVariableName), outFilePath.filename().string());
+            if(fs::exists(outFilePath))
+            {
+              // Only overwrite if input file is newer than output file
+              fs::file_time_type inFileTime = fs::last_write_time(path);
+              fs::file_time_type outFileTime = fs::last_write_time(outFilePath);
+              if(outFileTime > inFileTime)
+              {
+                continue;
+              }
+            }
+            GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath);
+            shaderGenerated = true;
           }
           break;
         }
@@ -312,7 +324,7 @@ int GenerateShaderSources(fs::path inDir, fs::path outDir, const bool generateBu
     }
   }
 
-  if(generateBuiltInFiles)
+  if(generateBuiltInFiles && shaderGenerated)
   {
     generator.Generate();
   }
index 034d18e..025ebd9 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.3.18
+Version:    2.3.24
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT