Merge branch 'devel/master' into tizen
authorSeoyeon Kim <seoyeon2.kim@samsung.com>
Fri, 27 May 2022 01:53:33 +0000 (10:53 +0900)
committerSeoyeon Kim <seoyeon2.kim@samsung.com>
Fri, 27 May 2022 01:53:33 +0000 (10:53 +0900)
31 files changed:
automated-tests/src/dali/CMakeLists.txt
automated-tests/src/dali/utc-Dali-CircularQueue.cpp
automated-tests/src/dali/utc-Dali-DecoratedVisualRenderer.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-Renderer.cpp
automated-tests/src/dali/utc-Dali-Vector.cpp
automated-tests/src/dali/utc-Dali-VisualRenderer.cpp
dali/internal/event/animation/key-frame-channel.h
dali/internal/event/rendering/decorated-visual-renderer-impl.cpp [new file with mode: 0644]
dali/internal/event/rendering/decorated-visual-renderer-impl.h [new file with mode: 0644]
dali/internal/event/rendering/visual-renderer-impl.cpp
dali/internal/event/rendering/visual-renderer-impl.h
dali/internal/file.list
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h
dali/internal/update/common/discard-queue.cpp
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/manager/update-manager.cpp
dali/internal/update/rendering/scene-graph-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer.h
dali/public-api/common/dali-vector.h
dali/public-api/dali-core-version.cpp
dali/public-api/dali-core.h
dali/public-api/file.list
dali/public-api/rendering/decorated-visual-renderer.cpp [new file with mode: 0644]
dali/public-api/rendering/decorated-visual-renderer.h [new file with mode: 0644]
dali/public-api/signals/base-signal.cpp
dali/public-api/signals/base-signal.h
dali/public-api/signals/connection-tracker.cpp
dali/public-api/signals/connection-tracker.h
dali/public-api/signals/dali-signal.h
packaging/dali.spec

index 835a9d3..7c0ff3f 100644 (file)
@@ -24,6 +24,7 @@ SET(TC_SOURCES
         utc-Dali-ConstraintSource.cpp
         utc-Dali-Core.cpp
         utc-Dali-CustomActor.cpp
+        utc-Dali-DecoratedVisualRenderer.cpp
         utc-Dali-Degree.cpp
         utc-Dali-DistanceField.cpp
         utc-Dali-DrawableActor.cpp
@@ -69,7 +70,6 @@ SET(TC_SOURCES
         utc-Dali-Random.cpp
         utc-Dali-Rect.cpp
         utc-Dali-Renderer.cpp
-        utc-Dali-VisualRenderer.cpp
         utc-Dali-RenderTask.cpp
         utc-Dali-RenderTaskList.cpp
         utc-Dali-RotationGestureDetector.cpp
@@ -100,6 +100,7 @@ SET(TC_SOURCES
         utc-Dali-Vector3.cpp
         utc-Dali-Vector4.cpp
         utc-Dali-VertexBuffer.cpp
+        utc-Dali-VisualRenderer.cpp
         utc-Dali-WeakHandle.cpp
         utc-Dali-WheelEvent.cpp
 )
index e5c718c..881e29d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
  *
  */
 
+#define ENABLE_VECTOR_ASSERTS
+
 #include <dali-test-suite-utils.h>
 #include <dali/devel-api/common/circular-queue.h>
 #include <dali/public-api/dali-core.h>
diff --git a/automated-tests/src/dali/utc-Dali-DecoratedVisualRenderer.cpp b/automated-tests/src/dali/utc-Dali-DecoratedVisualRenderer.cpp
new file mode 100644 (file)
index 0000000..ab8eb18
--- /dev/null
@@ -0,0 +1,1030 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/common/capabilities.h>
+#include <dali/devel-api/common/stage.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/render-task-list-integ.h>
+#include <dali/public-api/dali-core.h>
+#include <cstdio>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-test-suite-utils.h>
+#include <mesh-builder.h>
+#include <test-trace-call-stack.h>
+#include "test-graphics-command-buffer.h"
+
+using namespace Dali;
+
+void decorated_visual_renderer_test_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void decorated_visual_renderer_test_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliDecoratedVisualRendererNew01(void)
+{
+  TestApplication application;
+
+  Geometry                geometry = CreateQuadGeometry();
+  Shader                  shader   = CreateShader();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  DALI_TEST_EQUALS((bool)renderer, true, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererNew02(void)
+{
+  TestApplication         application;
+  DecoratedVisualRenderer renderer;
+  DALI_TEST_EQUALS((bool)renderer, false, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererCopyConstructor(void)
+{
+  TestApplication application;
+
+  Geometry                geometry = CreateQuadGeometry();
+  Shader                  shader   = CreateShader();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  DecoratedVisualRenderer rendererCopy(renderer);
+  DALI_TEST_EQUALS((bool)rendererCopy, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererAssignmentOperator(void)
+{
+  TestApplication application;
+
+  Geometry                geometry = CreateQuadGeometry();
+  Shader                  shader   = CreateShader();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  DecoratedVisualRenderer renderer2;
+  DALI_TEST_EQUALS((bool)renderer2, false, TEST_LOCATION);
+
+  renderer2 = renderer;
+  DALI_TEST_EQUALS((bool)renderer2, true, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererMoveConstructor(void)
+{
+  TestApplication application;
+
+  Geometry                geometry = CreateQuadGeometry();
+  Shader                  shader   = Shader::New("vertexSrc", "fragmentSrc");
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+  DALI_TEST_CHECK(renderer);
+  DALI_TEST_EQUALS(1, renderer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR), Vector3::ONE, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Color::BLACK, TEST_LOCATION);
+
+  auto testColor           = Vector3(1.0f, 0.0f, 1.0f);
+  auto testBorderlineColor = Vector4(1.0f, 0.0f, 1.0f, 0.5f);
+  renderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, testColor);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, testBorderlineColor);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR), testColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), testBorderlineColor, TEST_LOCATION);
+
+  DecoratedVisualRenderer move = std::move(renderer);
+  DALI_TEST_CHECK(move);
+  DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(move.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR), testColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(move.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), testBorderlineColor, TEST_LOCATION);
+
+  DALI_TEST_CHECK(!renderer);
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererMoveAssignment(void)
+{
+  TestApplication application;
+
+  Geometry                geometry = CreateQuadGeometry();
+  Shader                  shader   = Shader::New("vertexSrc", "fragmentSrc");
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+  DALI_TEST_CHECK(renderer);
+  DALI_TEST_EQUALS(1, renderer.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR), Vector3::ONE, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Color::BLACK, TEST_LOCATION);
+
+  auto testColor           = Vector3(1.0f, 0.0f, 1.0f);
+  auto testBorderlineColor = Vector4(1.0f, 0.0f, 1.0f, 0.5f);
+  renderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, testColor);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, testBorderlineColor);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR), testColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), testBorderlineColor, TEST_LOCATION);
+
+  DecoratedVisualRenderer move;
+  move = std::move(renderer);
+  DALI_TEST_CHECK(move);
+  DALI_TEST_EQUALS(1, move.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(move.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR), testColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(move.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), testBorderlineColor, TEST_LOCATION);
+  DALI_TEST_CHECK(!renderer);
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererDownCast01(void)
+{
+  TestApplication application;
+
+  Geometry                geometry = CreateQuadGeometry();
+  Shader                  shader   = CreateShader();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  BaseHandle              handle(renderer);
+  DecoratedVisualRenderer renderer2 = DecoratedVisualRenderer::DownCast(handle);
+  DALI_TEST_EQUALS((bool)renderer2, true, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererDownCast02(void)
+{
+  TestApplication application;
+
+  Handle                  handle   = Handle::New(); // Create a custom object
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::DownCast(handle);
+  DALI_TEST_EQUALS((bool)renderer, false, TEST_LOCATION);
+  END_TEST;
+}
+
+// using a template to auto deduce the parameter types
+template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
+void TEST_RENDERER_PROPERTY(P1 renderer, P2 stringName, P3 type, P4 isWriteable, P5 isAnimateable, P6 isConstraintInput, P7 enumName, P8 LOCATION)
+{
+  DALI_TEST_EQUALS(renderer.GetPropertyName(enumName), stringName, LOCATION);
+  DALI_TEST_EQUALS(renderer.GetPropertyIndex(stringName), static_cast<Property::Index>(enumName), LOCATION);
+  DALI_TEST_EQUALS(renderer.GetPropertyType(enumName), type, LOCATION);
+  DALI_TEST_EQUALS(renderer.IsPropertyWritable(enumName), isWriteable, LOCATION);
+  DALI_TEST_EQUALS(renderer.IsPropertyAnimatable(enumName), isAnimateable, LOCATION);
+  DALI_TEST_EQUALS(renderer.IsPropertyAConstraintInput(enumName), isConstraintInput, LOCATION);
+}
+
+int UtcDaliDecoratedVisualRendererDefaultProperties(void)
+{
+  TestApplication         application;
+  Geometry                geometry           = CreateQuadGeometry();
+  Shader                  shader             = CreateShader();
+  DecoratedVisualRenderer renderer           = DecoratedVisualRenderer::New(geometry, shader);
+  VisualRenderer          baseVisualRenderer = VisualRenderer::New(geometry, shader);
+  Renderer                baseRenderer       = Renderer::New(geometry, shader);
+
+  DALI_TEST_EQUALS(baseRenderer.GetPropertyCount(), 27, TEST_LOCATION);
+  DALI_TEST_EQUALS(baseVisualRenderer.GetPropertyCount(), 27 + 8, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetPropertyCount(), 27 + 8 + 6, TEST_LOCATION);
+
+  TEST_RENDERER_PROPERTY(renderer, "cornerRadius", Property::VECTOR4, true, true, true, DecoratedVisualRenderer::Property::CORNER_RADIUS, TEST_LOCATION);
+  TEST_RENDERER_PROPERTY(renderer, "cornerRadiusPolicy", Property::FLOAT, true, false, true, DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, TEST_LOCATION);
+  TEST_RENDERER_PROPERTY(renderer, "borderlineWidth", Property::FLOAT, true, true, true, DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, TEST_LOCATION);
+  TEST_RENDERER_PROPERTY(renderer, "borderlineColor", Property::VECTOR4, true, true, true, DecoratedVisualRenderer::Property::BORDERLINE_COLOR, TEST_LOCATION);
+  TEST_RENDERER_PROPERTY(renderer, "borderlineOffset", Property::FLOAT, true, true, true, DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, TEST_LOCATION);
+  TEST_RENDERER_PROPERTY(renderer, "blurRadius", Property::FLOAT, true, true, true, DecoratedVisualRenderer::Property::BLUR_RADIUS, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererAnimatedProperty01(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that a decorated visual renderer property can be animated");
+
+  Shader                  shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry                geometry = CreateQuadGeometry();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  Property::Index cornerRadiusIndex = DecoratedVisualRenderer::Property::CORNER_RADIUS;
+  renderer.SetProperty(cornerRadiusIndex, Vector4(1.0f, 10.0f, 5.0f, 0.0f));
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(cornerRadiusIndex), Vector4(1.0f, 10.0f, 5.0f, 0.0f), 0.001f, TEST_LOCATION);
+
+  Animation animation = Animation::New(1.0f);
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, Vector4(1.0f, 0.0f, 1.0f, 0.0f));
+  keyFrames.Add(1.0f, Vector4(0.0f, 1.0f, 0.0f, 1.0f));
+  animation.AnimateBetween(Property(renderer, cornerRadiusIndex), keyFrames);
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(500);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(cornerRadiusIndex), Vector4(0.5f, 0.5f, 0.5f, 0.5f), TEST_LOCATION);
+
+  application.Render(400);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(cornerRadiusIndex), Vector4(0.1f, 0.9f, 0.1f, 0.9f), TEST_LOCATION);
+
+  application.Render(100);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(cornerRadiusIndex), Vector4(0.f, 1.f, 0.f, 1.f), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(cornerRadiusIndex), Vector4(0.f, 1.f, 0.f, 1.f), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererAnimatedProperty02(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that a decorated visual renderer property can be animated");
+
+  Shader                  shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry                geometry = CreateQuadGeometry();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  renderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS, Vector4(1.0f, 1.0f, 0.0f, 0.0f));
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, 1.0f);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, -1.0f);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BLUR_RADIUS, 0.0f);
+
+  application.SendNotification();
+  application.Render(0);
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS), Vector4(1.0f, 1.0f, 0.0f, 0.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), 1.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Vector4(1.0f, 0.0f, 0.0f, 1.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), -1.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS), 0.0f, 0.001f, TEST_LOCATION);
+
+  Animation animation = Animation::New(1.0f);
+  animation.AnimateBy(Property(renderer, DecoratedVisualRenderer::Property::CORNER_RADIUS), Vector4(10.0f, 100.0f, 100.0f, 10.0f));
+  animation.AnimateBy(Property(renderer, DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), 10.0f);
+  animation.AnimateBy(Property(renderer, DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Vector4(-1.0f, 1.0f, 1.0f, 0.0f));
+  animation.AnimateBy(Property(renderer, DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), 2.0f);
+  animation.AnimateBy(Property(renderer, DecoratedVisualRenderer::Property::BLUR_RADIUS), 20.0f);
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(500);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS), Vector4(6.0f, 51.0f, 50.0f, 5.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), 6.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Vector4(0.5f, 0.5f, 0.5f, 1.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), 0.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS), 10.0f, 0.001f, TEST_LOCATION);
+
+  application.Render(400);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS), Vector4(10.0f, 91.0f, 90.0f, 9.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), 10.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Vector4(0.1f, 0.9f, 0.9f, 1.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), 0.8f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS), 18.0f, 0.001f, TEST_LOCATION);
+
+  application.Render(100);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS), Vector4(11.0f, 101.0f, 100.0f, 10.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), 11.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Vector4(0.0f, 1.0f, 1.0f, 1.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), 1.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS), 20.0f, 0.001f, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS), Vector4(11.0f, 101.0f, 100.0f, 10.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), 11.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR), Vector4(0.0f, 1.0f, 1.0f, 1.0f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), 1.0f, 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS), 20.0f, 0.001f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+struct DecoratedVisualProperties
+{
+  DecoratedVisualProperties() = default;
+
+  DecoratedVisualProperties(Vector2 offset, Vector2 size, Vector2 origin, Vector2 pivot, Vector4 modes, Vector2 extraSize, Vector3 mixColor, float preMultipliedAlpha, Vector4 cornerRadius, float cornerRadiusPolicy, float borderlineWidth, Vector4 borderlineColor, float borderlineOffset, float blurRadius)
+  : mTransformOffset(offset),
+    mTransformSize(size),
+    mTransformOrigin(origin),
+    mTransformAnchorPoint(pivot),
+    mTransformOffsetSizeMode(modes),
+    mExtraSize(extraSize),
+    mMixColor(mixColor),
+    mPreMultipliedAlpha(preMultipliedAlpha),
+    mCornerRadius(cornerRadius),
+    mCornerRadiusPolicy(cornerRadiusPolicy),
+    mBorderlineWidth(borderlineWidth),
+    mBorderlineColor(borderlineColor),
+    mBorderlineOffset(borderlineOffset),
+    mBlurRadius(blurRadius)
+  {
+  }
+
+  Vector2 mTransformOffset{Vector2::ZERO};
+  Vector2 mTransformSize{Vector2::ONE};
+  Vector2 mTransformOrigin{Vector2::ZERO};
+  Vector2 mTransformAnchorPoint{Vector2::ZERO};
+  Vector4 mTransformOffsetSizeMode{Vector2::ZERO};
+  Vector2 mExtraSize{Vector2::ZERO};
+  Vector3 mMixColor{Vector3::ONE};
+  float   mPreMultipliedAlpha{0.0f};
+
+  Vector4 mCornerRadius{Vector4::ZERO};
+  float   mCornerRadiusPolicy{1.0f};
+  float   mBorderlineWidth{0.0f};
+  Vector4 mBorderlineColor{Vector4::ZERO};
+  float   mBorderlineOffset{0.0f};
+  float   mBlurRadius{0.0f};
+
+  static DecoratedVisualProperties GetPropsAt(float alpha, const DecoratedVisualProperties& start, const DecoratedVisualProperties& end)
+  {
+    DecoratedVisualProperties progress;
+    progress.mTransformOffset  = start.mTransformOffset + (end.mTransformOffset - start.mTransformOffset) * alpha;
+    progress.mTransformSize    = start.mTransformSize + (end.mTransformSize - start.mTransformSize) * alpha;
+    progress.mExtraSize        = start.mExtraSize + (end.mExtraSize - start.mExtraSize) * alpha;
+    progress.mMixColor         = start.mMixColor + (end.mMixColor - start.mMixColor) * alpha;
+    progress.mCornerRadius     = start.mCornerRadius + (end.mCornerRadius - start.mCornerRadius) * alpha;
+    progress.mBorderlineWidth  = start.mBorderlineWidth + (end.mBorderlineWidth - start.mBorderlineWidth) * alpha;
+    progress.mBorderlineColor  = start.mBorderlineColor + (end.mBorderlineColor - start.mBorderlineColor) * alpha;
+    progress.mBorderlineOffset = start.mBorderlineOffset + (end.mBorderlineOffset - start.mBorderlineOffset) * alpha;
+    progress.mBlurRadius       = start.mBlurRadius + (end.mBlurRadius - start.mBlurRadius) * alpha;
+
+    progress.mTransformOffsetSizeMode = end.mTransformOffsetSizeMode;
+    progress.mTransformOrigin         = end.mTransformOrigin;
+    progress.mTransformAnchorPoint    = end.mTransformAnchorPoint;
+    progress.mPreMultipliedAlpha      = end.mPreMultipliedAlpha;
+    progress.mCornerRadiusPolicy      = end.mCornerRadiusPolicy;
+    return progress;
+  }
+};
+
+void PrintDecoratedVisualProperties(const DecoratedVisualProperties& props, const std::string& prefix)
+{
+  tet_printf(
+    "%s: offset:(%5.3f, %5.3f)\n"
+    "%*c size:(%5.3f, %5.3f)\n"
+    "%*c origin:(%5.3f, %5.3f)\n"
+    "%*c anchorPoint:(%5.3f, %5.3f)\n"
+    "%*c offsetSizeMode:(%5.3f, %5.3f, %5.3f, %5.3f)\n"
+    "%*c extraSize:(%5.3f, %5.3f)\n"
+    "%*c mixColor:(%5.3f, %5.3f, %5.3f)\n"
+    "%*c preMultipliedAlpha:(%5.3f)\n"
+    "%*c cornerRadius:(%5.3f, %5.3f, %5.3f, %5.3f)\n"
+    "%*c cornerRadiusPolicy:(%5.3f)\n"
+    "%*c borderlineWidth:(%5.3f)\n"
+    "%*c borderlineColor:(%5.3f, %5.3f, %5.3f, %5.3f)\n"
+    "%*c borderlineOffset:(%5.3f)\n"
+    "%*c blurRadius:(%5.3f)\n",
+    prefix.c_str(),
+    props.mTransformOffset.x,
+    props.mTransformOffset.y,
+    prefix.length() + 1,
+    ' ',
+    props.mTransformSize.x,
+    props.mTransformSize.y,
+    prefix.length() + 1,
+    ' ',
+    props.mTransformOrigin.x,
+    props.mTransformOrigin.y,
+    prefix.length() + 1,
+    ' ',
+    props.mTransformAnchorPoint.x,
+    props.mTransformAnchorPoint.y,
+    prefix.length() + 1,
+    ' ',
+    props.mTransformOffsetSizeMode.x,
+    props.mTransformOffsetSizeMode.y,
+    props.mTransformOffsetSizeMode.z,
+    props.mTransformOffsetSizeMode.w,
+    prefix.length() + 1,
+    ' ',
+    props.mExtraSize.x,
+    props.mExtraSize.y,
+    prefix.length() + 1,
+    ' ',
+    props.mMixColor.x,
+    props.mMixColor.y,
+    props.mMixColor.z,
+    prefix.length() + 1,
+    ' ',
+    props.mPreMultipliedAlpha,
+    prefix.length() + 1,
+    ' ',
+    props.mCornerRadius.x,
+    props.mCornerRadius.y,
+    props.mCornerRadius.z,
+    props.mCornerRadius.w,
+    prefix.length() + 1,
+    ' ',
+    props.mCornerRadiusPolicy,
+    prefix.length() + 1,
+    ' ',
+    props.mBorderlineWidth,
+    prefix.length() + 1,
+    ' ',
+    props.mBorderlineColor.x,
+    props.mBorderlineColor.y,
+    props.mBorderlineColor.z,
+    props.mBorderlineColor.w,
+    prefix.length() + 1,
+    ' ',
+    props.mBorderlineOffset,
+    prefix.length() + 1,
+    ' ',
+    props.mBlurRadius);
+}
+
+void SetDecoratedVisualProperties(DecoratedVisualRenderer renderer, DecoratedVisualProperties props)
+{
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, props.mTransformOffset);
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, props.mTransformSize);
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_ORIGIN, props.mTransformOrigin);
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_ANCHOR_POINT, props.mTransformAnchorPoint);
+  renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET_SIZE_MODE, props.mTransformOffsetSizeMode);
+  renderer.SetProperty(VisualRenderer::Property::EXTRA_SIZE, props.mExtraSize);
+  renderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, props.mMixColor);
+  renderer.SetProperty(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA, props.mPreMultipliedAlpha);
+
+  renderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS, props.mCornerRadius);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, props.mCornerRadiusPolicy);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, props.mBorderlineWidth);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_COLOR, props.mBorderlineColor);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, props.mBorderlineOffset);
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BLUR_RADIUS, props.mBlurRadius);
+}
+
+void CheckEventDecoratedVisualProperties(DecoratedVisualRenderer renderer, DecoratedVisualProperties expectedProps)
+{
+  tet_infoline("CheckEventDecoratedVisualProperties\n");
+
+  DecoratedVisualProperties actualProps;
+  actualProps.mTransformOffset         = renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_OFFSET);
+  actualProps.mTransformSize           = renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE);
+  actualProps.mTransformOrigin         = renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_ORIGIN);
+  actualProps.mTransformAnchorPoint    = renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_ANCHOR_POINT);
+  actualProps.mTransformOffsetSizeMode = renderer.GetProperty<Vector4>(VisualRenderer::Property::TRANSFORM_OFFSET_SIZE_MODE);
+  actualProps.mExtraSize               = renderer.GetProperty<Vector2>(VisualRenderer::Property::EXTRA_SIZE);
+  actualProps.mMixColor                = renderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR);
+  actualProps.mPreMultipliedAlpha      = renderer.GetProperty<float>(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA);
+
+  actualProps.mCornerRadius       = renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS);
+  actualProps.mCornerRadiusPolicy = renderer.GetProperty<float>(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY);
+  actualProps.mBorderlineWidth    = renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH);
+  actualProps.mBorderlineColor    = renderer.GetProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR);
+  actualProps.mBorderlineOffset   = renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET);
+  actualProps.mBlurRadius         = renderer.GetProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS);
+
+  PrintDecoratedVisualProperties(actualProps, "Actual event props");
+
+  DALI_TEST_EQUALS(actualProps.mTransformOffset, expectedProps.mTransformOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformSize, expectedProps.mTransformSize, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformOrigin, expectedProps.mTransformOrigin, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformAnchorPoint, expectedProps.mTransformAnchorPoint, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformOffsetSizeMode, expectedProps.mTransformOffsetSizeMode, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mExtraSize, expectedProps.mExtraSize, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mMixColor, expectedProps.mMixColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mPreMultipliedAlpha, expectedProps.mPreMultipliedAlpha, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(actualProps.mCornerRadius, expectedProps.mCornerRadius, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mCornerRadiusPolicy, expectedProps.mCornerRadiusPolicy, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBorderlineWidth, expectedProps.mBorderlineWidth, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBorderlineColor, expectedProps.mBorderlineColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBorderlineOffset, expectedProps.mBorderlineOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBlurRadius, expectedProps.mBlurRadius, TEST_LOCATION);
+}
+
+void CheckSceneGraphDecoratedVisualProperties(DecoratedVisualRenderer renderer, DecoratedVisualProperties expectedProps)
+{
+  tet_infoline("CheckSceneGraphVisualProperties\n");
+
+  DecoratedVisualProperties actualProps;
+
+  actualProps.mTransformOffset         = renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_OFFSET);
+  actualProps.mTransformSize           = renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE);
+  actualProps.mTransformOrigin         = renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_ORIGIN);
+  actualProps.mTransformAnchorPoint    = renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_ANCHOR_POINT);
+  actualProps.mTransformOffsetSizeMode = renderer.GetCurrentProperty<Vector4>(VisualRenderer::Property::TRANSFORM_OFFSET_SIZE_MODE);
+  actualProps.mExtraSize               = renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::EXTRA_SIZE);
+  actualProps.mMixColor                = renderer.GetCurrentProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR);
+
+  actualProps.mCornerRadius       = renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::CORNER_RADIUS);
+  actualProps.mCornerRadiusPolicy = renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY);
+  actualProps.mBorderlineWidth    = renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH);
+  actualProps.mBorderlineColor    = renderer.GetCurrentProperty<Vector4>(DecoratedVisualRenderer::Property::BORDERLINE_COLOR);
+  actualProps.mBorderlineOffset   = renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BORDERLINE_OFFSET);
+  actualProps.mBlurRadius         = renderer.GetCurrentProperty<float>(DecoratedVisualRenderer::Property::BLUR_RADIUS);
+
+  PrintDecoratedVisualProperties(actualProps, "Actual update props");
+
+  DALI_TEST_EQUALS(actualProps.mTransformOffset, expectedProps.mTransformOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformSize, expectedProps.mTransformSize, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformOrigin, expectedProps.mTransformOrigin, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformAnchorPoint, expectedProps.mTransformAnchorPoint, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mTransformOffsetSizeMode, expectedProps.mTransformOffsetSizeMode, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mExtraSize, expectedProps.mExtraSize, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mMixColor, expectedProps.mMixColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mPreMultipliedAlpha, expectedProps.mPreMultipliedAlpha, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(actualProps.mCornerRadius, expectedProps.mCornerRadius, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mCornerRadiusPolicy, expectedProps.mCornerRadiusPolicy, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBorderlineWidth, expectedProps.mBorderlineWidth, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBorderlineColor, expectedProps.mBorderlineColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBorderlineOffset, expectedProps.mBorderlineOffset, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mBlurRadius, expectedProps.mBlurRadius, TEST_LOCATION);
+}
+
+void CheckUniforms(DecoratedVisualRenderer renderer, DecoratedVisualProperties props, std::vector<UniformData>& uniforms, TraceCallStack& callStack, TestGlAbstraction& gl)
+{
+  tet_infoline("CheckUniforms\n");
+
+  TraceCallStack::NamedParams params;
+
+  tet_printf("Callback trace: \n%s\n", callStack.GetTraceString().c_str());
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[0].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector2>(uniforms[0].name.c_str(), props.mTransformOffset));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[1].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector2>(uniforms[1].name.c_str(), props.mTransformSize));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[2].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector2>(uniforms[2].name.c_str(), props.mTransformOrigin));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[3].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector2>(uniforms[3].name.c_str(), props.mTransformAnchorPoint));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[4].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector4>(uniforms[4].name.c_str(), props.mTransformOffsetSizeMode));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[5].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector2>(uniforms[5].name.c_str(), props.mExtraSize));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[6].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector3>(uniforms[6].name.c_str(), props.mMixColor));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[7].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<float>(uniforms[7].name.c_str(), props.mPreMultipliedAlpha));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[8].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector4>(uniforms[8].name.c_str(), props.mCornerRadius));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[9].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<float>(uniforms[9].name.c_str(), props.mCornerRadiusPolicy));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[10].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<float>(uniforms[10].name.c_str(), props.mBorderlineWidth));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[11].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<Vector4>(uniforms[11].name.c_str(), props.mBorderlineColor));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[12].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<float>(uniforms[12].name.c_str(), props.mBorderlineOffset));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[13].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<float>(uniforms[13].name.c_str(), props.mBlurRadius));
+}
+
+int UtcDaliDecoratedVisualRendererAnimatedProperty03(void)
+{
+  TestApplication    application;
+  TestGlAbstraction& gl        = application.GetGlAbstraction();
+  TraceCallStack&    callStack = gl.GetSetUniformTrace();
+  gl.EnableSetUniformCallTrace(true);
+
+  tet_infoline("Test that a decorated visual renderer property can be animated and that the uniforms are set");
+
+  std::vector<UniformData> customUniforms{{"offset", Property::VECTOR2},
+                                          {"size", Property::VECTOR2},
+                                          {"origin", Property::VECTOR2},
+                                          {"anchorPoint", Property::VECTOR2},
+                                          {"offsetSizeMode", Property::VECTOR4},
+                                          {"extraSize", Property::VECTOR2},
+                                          {"mixColor", Property::VECTOR3},
+                                          {"preMultipliedAlpha", Property::FLOAT},
+                                          {"cornerRadius", Property::VECTOR4},
+                                          {"cornerRadiusPolicy", Property::FLOAT},
+                                          {"borderlineWidth", Property::FLOAT},
+                                          {"borderlineColor", Property::VECTOR4},
+                                          {"borderlineOffset", Property::FLOAT},
+                                          {"blurRadius", Property::FLOAT}};
+
+  application.GetGraphicsController().AddCustomUniforms(customUniforms);
+
+  Shader                  shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry                geometry = CreateQuadGeometry();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  // Add all uniform mappings
+  renderer.RegisterCornerRadiusUniform();
+  renderer.RegisterBorderlineUniform();
+  renderer.RegisterBlurRadiusUniform();
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  DecoratedVisualProperties props{Vector2(10.f, 10.f), Vector2(200.f, 100.f), Vector2(0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector4::ZERO, Vector2(0.0f, 0.0f), Vector3(Color::SEA_GREEN), 0.0f, Vector4(100.0f, 10.0f, 1.0f, 0.1f), 1.0f, 20.0f, Vector4(1.0f, 0.0f, 1.0f, 0.5f), 1.0f, 10.0f};
+  DecoratedVisualProperties targetProps{Vector2(40.f, 40.f), Vector2(100.f, 200.f), Vector2(0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector4::ZERO, Vector2(25.0f, 25.0f), Vector3(Color::MEDIUM_PURPLE), 0.0f, Vector4(0.2f, 2.0f, 20.0f, 200.0f), 1.0f, 40.0f, Vector4(0.0f, 0.2f, 0.0f, 1.0f), -1.0f, 2.0f};
+
+  SetDecoratedVisualProperties(renderer, props);
+  CheckEventDecoratedVisualProperties(renderer, props);
+  application.SendNotification();
+  application.Render(0);
+  CheckSceneGraphDecoratedVisualProperties(renderer, props);
+  CheckUniforms(renderer, props, customUniforms, callStack, gl);
+
+  // Set up a 1 second anim.
+  Animation animation = Animation::New(1.0f);
+
+  animation.AnimateTo(Property(renderer, VisualRenderer::Property::TRANSFORM_OFFSET), targetProps.mTransformOffset);
+  animation.AnimateTo(Property(renderer, VisualRenderer::Property::TRANSFORM_SIZE), targetProps.mTransformSize);
+  animation.AnimateTo(Property(renderer, VisualRenderer::Property::EXTRA_SIZE), targetProps.mExtraSize);
+  animation.AnimateTo(Property(renderer, VisualRenderer::Property::VISUAL_MIX_COLOR), targetProps.mMixColor);
+
+  animation.AnimateTo(Property(renderer, DecoratedVisualRenderer::Property::CORNER_RADIUS), targetProps.mCornerRadius);
+  animation.AnimateTo(Property(renderer, DecoratedVisualRenderer::Property::BORDERLINE_WIDTH), targetProps.mBorderlineWidth);
+  animation.AnimateTo(Property(renderer, DecoratedVisualRenderer::Property::BORDERLINE_COLOR), targetProps.mBorderlineColor);
+  animation.AnimateTo(Property(renderer, DecoratedVisualRenderer::Property::BORDERLINE_OFFSET), targetProps.mBorderlineOffset);
+  animation.AnimateTo(Property(renderer, DecoratedVisualRenderer::Property::BLUR_RADIUS), targetProps.mBlurRadius);
+  animation.Play();
+
+  CheckEventDecoratedVisualProperties(renderer, targetProps);
+
+  for(int i = 0; i <= 10; ++i)
+  {
+    tet_printf("\n###########  Animation progress: %d%%\n\n", i * 10);
+    DecoratedVisualProperties propsProgress = DecoratedVisualProperties::GetPropsAt(0.1f * i, props, targetProps);
+    PrintDecoratedVisualProperties(propsProgress, "Expected values");
+
+    callStack.Reset();
+    application.SendNotification();
+    application.Render((i == 0 ? 0 : 100));
+
+    CheckEventDecoratedVisualProperties(renderer, targetProps);
+
+    CheckSceneGraphDecoratedVisualProperties(renderer, propsProgress);
+    CheckUniforms(renderer, propsProgress, customUniforms, callStack, gl);
+  }
+
+  // Ensure animation finishes
+  application.SendNotification();
+  application.Render(100);
+  CheckSceneGraphDecoratedVisualProperties(renderer, targetProps);
+  CheckUniforms(renderer, targetProps, customUniforms, callStack, gl);
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererAnimatedProperty04(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that a decorated visual renderer property can't be animated");
+
+  Shader                  shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry                geometry = CreateQuadGeometry();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  Property::Index index = DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY;
+  renderer.SetProperty(index, 0.0f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(index), 0.0f, 0.001f, TEST_LOCATION);
+
+  Animation animation = Animation::New(1.0f);
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, 0.0f);
+  keyFrames.Add(1.0f, 1.0f);
+  try
+  {
+    animation.AnimateBetween(Property(renderer, index), keyFrames);
+    tet_result(TET_FAIL);
+  }
+  catch(DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "baseProperty && \"Property is not animatable\"", TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererAnimatedProperty05(void)
+{
+  TestApplication application;
+
+  tet_infoline("Test that a parent visual renderer property can still be animated");
+
+  Shader                  shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry                geometry = CreateQuadGeometry();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  application.GetScene().Add(actor);
+
+  Property::Index index = VisualRenderer::Property::TRANSFORM_SIZE;
+  renderer.SetProperty(index, Vector2(1.0f, 0.5f));
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector2>(index), Vector2(1.0f, 0.5f), 0.001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE), Vector2(1.0f, 0.5f), 0.0001f, TEST_LOCATION);
+
+  Animation animation = Animation::New(1.0f);
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, Vector2(1.0f, 0.0f));
+  keyFrames.Add(1.0f, Vector2(0.0f, 1.0f));
+  animation.AnimateBetween(Property(renderer, index), keyFrames);
+  animation.Play();
+
+  application.SendNotification();
+
+  // Test that the event side properties are set to target value of (0, 1)
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE), Vector2(0.0f, 1.0f), 0.0001f, TEST_LOCATION);
+
+  application.Render(500);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(index), Vector2(0.5f, 0.5f), 0.0001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE), Vector2(0.5f, 0.5f), 0.0001f, TEST_LOCATION);
+
+  // Test that the event side properties are set to target value 0f (0, 1)
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE), Vector2(0.0f, 1.0f), 0.0001f, TEST_LOCATION);
+
+  // Complete the animation
+  application.Render(500);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(index), Vector2(0.0f, 1.0f), 0.0001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE), Vector2(0.0f, 1.0f), 0.0001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector2>(VisualRenderer::Property::TRANSFORM_SIZE), Vector2(0.0f, 1.0f), 0.0001f, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliDecoratedVisualRendererPartialUpdate(void)
+{
+  TestApplication application(
+    TestApplication::DEFAULT_SURFACE_WIDTH,
+    TestApplication::DEFAULT_SURFACE_HEIGHT,
+    TestApplication::DEFAULT_HORIZONTAL_DPI,
+    TestApplication::DEFAULT_VERTICAL_DPI,
+    true,
+    true);
+
+  tet_infoline("Test that partial update works well when we set visual renderer's animated properties");
+
+  const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+  Shader                  shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry                geometry = CreateQuadGeometry();
+  DecoratedVisualRenderer renderer = DecoratedVisualRenderer::New(geometry, shader);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT;
+  actor[Actor::Property::POSITION]     = Vector3(64.0f, 64.0f, 0.0f);
+  actor[Actor::Property::SIZE]         = Vector3(64.0f, 64.0f, 0.0f);
+  actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+
+  std::vector<Rect<int>> damagedRects;
+
+  // Actor added, damaged rect is added size of actor
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+  // Aligned by 16
+  Rect<int> clippingRect = Rect<int>(64, 672, 80, 80); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Set clippingRect as full surface now. TODO : Set valid rect if we can.
+  clippingRect = TestApplication::DEFAULT_SURFACE_RECT;
+
+  // Set decoration with borderline as 32 units.
+  renderer.RegisterBorderlineUniform();
+  renderer.SetProperty(DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, 32.0f);
+
+  Property::Index index = DecoratedVisualRenderer::Property::BORDERLINE_OFFSET;
+  renderer.SetProperty(index, 1.0f);
+
+  // Now current actor show as 128x128 rectangle, with center position (96, 96).
+  // So, rectangle's top left position is (32, 32), and bottom right position is (160, 160).
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(32, 640, 144, 144), damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::BLUE);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(32, 640, 144, 144), damagedRects[0], TEST_LOCATION);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // 3 frame spended after change actor property. Ensure the damaged rect is empty
+  DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(index), 1.0f, 0.001f, TEST_LOCATION);
+
+  // Make flickered animation from 1.0f --> 0.0f --> -1.0f of borderline offset
+  // After finish the animation, actor show as 64x64 rectangle, with center position (96, 96).
+  // So, rectangle's top left position is (64, 64), and bottom right position is (128, 128).
+  Animation animation = Animation::New(1.0f);
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, float(1.0f));
+  keyFrames.Add(0.299f, float(1.0f));
+  keyFrames.Add(0.301f, float(0.0f));
+  keyFrames.Add(0.699f, float(0.0f));
+  keyFrames.Add(0.701f, float(-1.0f));
+  keyFrames.Add(1.0f, float(-1.0f));
+  animation.AnimateBetween(Property(renderer, index), keyFrames);
+  animation.Play();
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(200, nullptr, damagedRects); // 200 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(index), 1.0f, TEST_LOCATION);
+
+  // 302 ~ 600. TransformSize become 0.0f
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(102, nullptr, damagedRects); // 302 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(index), 0.0f, TEST_LOCATION);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 318 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::GREEN);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 334 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 350 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  // Now current actor show as 96x96 rectangle, with center position (96, 96).
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(48, 656, 112, 112), damagedRects[0], TEST_LOCATION);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(250, nullptr, damagedRects); // 600 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // 702 ~ 1000. TransformSize become -1.0f
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(102, nullptr, damagedRects); // 702 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<float>(index), -1.0f, TEST_LOCATION);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::GREEN);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 718 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::BLUE);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 734 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 750 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  // Now current actor show as 64x64 rectangle, with center position (96, 96).
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(64, 672, 80, 80), damagedRects[0], TEST_LOCATION);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(52, nullptr, damagedRects); // 1002 ms. animation finished.
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Check finished value bake.
+  DALI_TEST_EQUALS(renderer.GetProperty<float>(index), -1.0f, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index ba640e0..0ae0595 100644 (file)
@@ -3521,6 +3521,85 @@ int UtcDaliRendererRegenerateUniformMap(void)
   END_TEST;
 }
 
+int UtcDaliRendererRenderAfterAddShader(void)
+{
+  TestApplication    application;
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+
+  tet_infoline("Test regenerating uniform map when shader changed");
+
+  Geometry geometry = CreateQuadGeometry();
+  Shader   shader1  = Shader::New("vertexSrc1", "fragmentSrc1");
+  Shader   shader2  = Shader::New("vertexSrc2", "fragmentSrc2");
+  Renderer renderer = Renderer::New(geometry, shader1);
+
+  // Register each shader1 and shader2 only had
+  shader1.RegisterProperty("uUniform1", Color::CRIMSON);
+  shader2.RegisterProperty("uShader2Only", Color::AQUA_MARINE);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
+  actor.SetProperty(Actor::Property::COLOR, Vector4(1.0f, 0.0f, 1.0f, 1.0f));
+  application.GetScene().Add(actor);
+
+  Property::Value value = renderer.GetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR);
+  int             renderingBehavior;
+  DALI_TEST_CHECK(value.Get(renderingBehavior));
+  DALI_TEST_EQUALS(static_cast<DevelRenderer::Rendering::Type>(renderingBehavior), DevelRenderer::Rendering::IF_REQUIRED, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Check uUniform1 rendered and uUniform2 not rendered before
+  Vector4 actualValue(Vector4::ZERO);
+  DALI_TEST_CHECK(glAbstraction.GetUniformValue<Vector4>("uUniform1", actualValue));
+  DALI_TEST_EQUALS(actualValue, Color::CRIMSON, TEST_LOCATION);
+
+  uint32_t updateStatus = application.GetUpdateStatus();
+
+  DALI_TEST_CHECK(!(updateStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING));
+
+  // Update for several frames
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+  drawTrace.Enable(true);
+  drawTrace.Reset();
+
+  std::vector<UniformData> customUniforms{{"uShader2Only", Property::VECTOR4}};
+
+  application.GetGraphicsController().AddCustomUniforms(customUniforms);
+
+  // Change shader.
+  renderer.SetShader(shader2);
+
+  // Render and check the update status
+  application.SendNotification();
+  application.Render(0);
+
+  updateStatus = application.GetUpdateStatus();
+
+  DALI_TEST_CHECK(!(updateStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING));
+
+  DALI_TEST_EQUALS(drawTrace.CountMethod("DrawElements"), 1, TEST_LOCATION);
+
+  // Check uUniform2 rendered now
+  DALI_TEST_CHECK(glAbstraction.GetUniformValue<Vector4>("uShader2Only", actualValue));
+  DALI_TEST_EQUALS(actualValue, Color::AQUA_MARINE, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliRendererAddDrawCommands(void)
 {
   TestApplication application;
index 815cf69..b6ae5bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
  *
  */
 
+#define ENABLE_VECTOR_ASSERTS
+
 #include <dali-test-suite-utils.h>
 #include <dali/public-api/dali-core.h>
 #include <stdlib.h>
index 2b589e9..b274772 100644 (file)
@@ -300,24 +300,26 @@ struct VisualProperties
 {
   VisualProperties() = default;
 
-  VisualProperties(Vector2 offset, Vector2 size, Vector2 origin, Vector2 pivot, Vector4 modes, Vector2 extraSize, Vector3 mixColor)
+  VisualProperties(Vector2 offset, Vector2 size, Vector2 origin, Vector2 pivot, Vector4 modes, Vector2 extraSize, Vector3 mixColor, float preMultipliedAlpha)
   : mTransformOffset(offset),
     mTransformSize(size),
     mTransformOrigin(origin),
     mTransformAnchorPoint(pivot),
     mTransformOffsetSizeMode(modes),
     mExtraSize(extraSize),
-    mMixColor(mixColor)
+    mMixColor(mixColor),
+    mPreMultipliedAlpha(preMultipliedAlpha)
   {
   }
 
   Vector2 mTransformOffset{Vector2::ZERO};
-  Vector2 mTransformSize{Vector2::ZERO};
+  Vector2 mTransformSize{Vector2::ONE};
   Vector2 mTransformOrigin{Vector2::ZERO};
   Vector2 mTransformAnchorPoint{Vector2::ZERO};
   Vector4 mTransformOffsetSizeMode{Vector2::ZERO};
   Vector2 mExtraSize{Vector2::ZERO};
   Vector3 mMixColor{Vector3::ONE};
+  float   mPreMultipliedAlpha{0.0f};
 
   static VisualProperties GetPropsAt(float alpha, const VisualProperties& start, const VisualProperties& end)
   {
@@ -329,6 +331,7 @@ struct VisualProperties
     progress.mTransformOffsetSizeMode = end.mTransformOffsetSizeMode;
     progress.mTransformOrigin         = end.mTransformOrigin;
     progress.mTransformAnchorPoint    = end.mTransformAnchorPoint;
+    progress.mPreMultipliedAlpha      = end.mPreMultipliedAlpha;
     return progress;
   }
 };
@@ -342,37 +345,41 @@ void PrintVisualProperties(const VisualProperties& props, const std::string& pre
     "%*c anchorPoint:(%5.3f, %5.3f)\n"
     "%*c offsetSizeMode:(%5.3f, %5.3f, %5.3f, %5.3f)\n"
     "%*c extraSize:(%5.3f, %5.3f)\n"
-    "%*c mixColor:(%5.3f, %5.3f, %5.3f, %5.3f)\n",
+    "%*c mixColor:(%5.3f, %5.3f, %5.3f)\n"
+    "%*c preMultipliedAlpha:(%5.3f)\n",
     prefix.c_str(),
     props.mTransformOffset.x,
     props.mTransformOffset.y,
-    prefix.length(),
+    prefix.length() + 1,
     ' ',
     props.mTransformSize.x,
     props.mTransformSize.y,
-    prefix.length(),
+    prefix.length() + 1,
     ' ',
     props.mTransformOrigin.x,
     props.mTransformOrigin.y,
-    prefix.length(),
+    prefix.length() + 1,
     ' ',
     props.mTransformAnchorPoint.x,
     props.mTransformAnchorPoint.y,
-    prefix.length(),
+    prefix.length() + 1,
     ' ',
     props.mTransformOffsetSizeMode.x,
     props.mTransformOffsetSizeMode.y,
     props.mTransformOffsetSizeMode.z,
     props.mTransformOffsetSizeMode.w,
-    prefix.length(),
+    prefix.length() + 1,
     ' ',
     props.mExtraSize.x,
     props.mExtraSize.y,
-    prefix.length(),
+    prefix.length() + 1,
     ' ',
     props.mMixColor.x,
     props.mMixColor.y,
-    props.mMixColor.z);
+    props.mMixColor.z,
+    prefix.length() + 1,
+    ' ',
+    props.mPreMultipliedAlpha);
 }
 
 void SetVisualProperties(VisualRenderer renderer, VisualProperties props)
@@ -384,6 +391,7 @@ void SetVisualProperties(VisualRenderer renderer, VisualProperties props)
   renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET_SIZE_MODE, props.mTransformOffsetSizeMode);
   renderer.SetProperty(VisualRenderer::Property::EXTRA_SIZE, props.mExtraSize);
   renderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, props.mMixColor);
+  renderer.SetProperty(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA, props.mPreMultipliedAlpha);
 }
 
 void CheckEventVisualProperties(VisualRenderer renderer, VisualProperties expectedProps)
@@ -398,6 +406,7 @@ void CheckEventVisualProperties(VisualRenderer renderer, VisualProperties expect
   actualProps.mTransformOffsetSizeMode = renderer.GetProperty<Vector4>(VisualRenderer::Property::TRANSFORM_OFFSET_SIZE_MODE);
   actualProps.mExtraSize               = renderer.GetProperty<Vector2>(VisualRenderer::Property::EXTRA_SIZE);
   actualProps.mMixColor                = renderer.GetProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR);
+  actualProps.mPreMultipliedAlpha      = renderer.GetProperty<float>(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA);
 
   PrintVisualProperties(actualProps, "Actual event props");
 
@@ -408,6 +417,7 @@ void CheckEventVisualProperties(VisualRenderer renderer, VisualProperties expect
   DALI_TEST_EQUALS(actualProps.mTransformOffsetSizeMode, expectedProps.mTransformOffsetSizeMode, TEST_LOCATION);
   DALI_TEST_EQUALS(actualProps.mExtraSize, expectedProps.mExtraSize, TEST_LOCATION);
   DALI_TEST_EQUALS(actualProps.mMixColor, expectedProps.mMixColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mPreMultipliedAlpha, expectedProps.mPreMultipliedAlpha, TEST_LOCATION);
 }
 
 void CheckSceneGraphVisualProperties(VisualRenderer renderer, VisualProperties expectedProps)
@@ -423,6 +433,7 @@ void CheckSceneGraphVisualProperties(VisualRenderer renderer, VisualProperties e
   actualProps.mTransformOffsetSizeMode = renderer.GetCurrentProperty<Vector4>(VisualRenderer::Property::TRANSFORM_OFFSET_SIZE_MODE);
   actualProps.mExtraSize               = renderer.GetCurrentProperty<Vector2>(VisualRenderer::Property::EXTRA_SIZE);
   actualProps.mMixColor                = renderer.GetCurrentProperty<Vector3>(VisualRenderer::Property::VISUAL_MIX_COLOR);
+  actualProps.mPreMultipliedAlpha      = renderer.GetProperty<float>(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA);
 
   PrintVisualProperties(actualProps, "Actual update props");
 
@@ -433,6 +444,7 @@ void CheckSceneGraphVisualProperties(VisualRenderer renderer, VisualProperties e
   DALI_TEST_EQUALS(actualProps.mTransformOffsetSizeMode, expectedProps.mTransformOffsetSizeMode, TEST_LOCATION);
   DALI_TEST_EQUALS(actualProps.mExtraSize, expectedProps.mExtraSize, TEST_LOCATION);
   DALI_TEST_EQUALS(actualProps.mMixColor, expectedProps.mMixColor, TEST_LOCATION);
+  DALI_TEST_EQUALS(actualProps.mPreMultipliedAlpha, expectedProps.mPreMultipliedAlpha, TEST_LOCATION);
 }
 
 void CheckUniforms(VisualRenderer renderer, VisualProperties props, std::vector<UniformData>& uniforms, TraceCallStack& callStack, TestGlAbstraction& gl)
@@ -463,6 +475,9 @@ void CheckUniforms(VisualRenderer renderer, VisualProperties props, std::vector<
 
   DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[6].name, params));
   DALI_TEST_CHECK(gl.GetUniformValue<Vector3>(uniforms[6].name.c_str(), props.mMixColor));
+
+  DALI_TEST_CHECK(callStack.FindMethodAndGetParameters(uniforms[7].name, params));
+  DALI_TEST_CHECK(gl.GetUniformValue<float>(uniforms[7].name.c_str(), props.mPreMultipliedAlpha));
 }
 
 int UtcDaliVisualRendererAnimatedProperty03(void)
@@ -480,7 +495,8 @@ int UtcDaliVisualRendererAnimatedProperty03(void)
                                           {"anchorPoint", Property::VECTOR2},
                                           {"offsetSizeMode", Property::VECTOR4},
                                           {"extraSize", Property::VECTOR2},
-                                          {"mixColor", Property::VECTOR3}};
+                                          {"mixColor", Property::VECTOR3},
+                                          {"preMultipliedAlpha", Property::FLOAT}};
 
   application.GetGraphicsController().AddCustomUniforms(customUniforms);
 
@@ -493,8 +509,8 @@ int UtcDaliVisualRendererAnimatedProperty03(void)
   actor.SetProperty(Actor::Property::SIZE, Vector2(400.0f, 400.0f));
   application.GetScene().Add(actor);
 
-  VisualProperties props{Vector2(10.f, 10.f), Vector2(200.f, 100.f), Vector2(0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector4::ZERO, Vector2(0.0f, 0.0f), Vector3(Color::SEA_GREEN)};
-  VisualProperties targetProps{Vector2(40.f, 40.f), Vector2(100.f, 200.f), Vector2(0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector4::ZERO, Vector2(25.0f, 25.0f), Vector3(Color::MEDIUM_PURPLE)};
+  VisualProperties props{Vector2(10.f, 10.f), Vector2(200.f, 100.f), Vector2(0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector4::ZERO, Vector2(0.0f, 0.0f), Vector3(Color::SEA_GREEN), 0.0f};
+  VisualProperties targetProps{Vector2(40.f, 40.f), Vector2(100.f, 200.f), Vector2(0.5f, 0.5f), Vector2(0.5f, 0.5f), Vector4::ZERO, Vector2(25.0f, 25.0f), Vector3(Color::MEDIUM_PURPLE), 0.0f};
 
   SetVisualProperties(renderer, props);
   CheckEventVisualProperties(renderer, props);
@@ -671,3 +687,231 @@ int UtcDaliVisualRendererAnimatedProperty06(void)
   DALI_TEST_EQUALS(renderer.GetProperty<float>(DevelRenderer::Property::OPACITY), 0.0f, 0.0001f, TEST_LOCATION);
   END_TEST;
 }
+
+int UtcDaliVisualRendererPartialUpdate(void)
+{
+  TestApplication application(
+    TestApplication::DEFAULT_SURFACE_WIDTH,
+    TestApplication::DEFAULT_SURFACE_HEIGHT,
+    TestApplication::DEFAULT_HORIZONTAL_DPI,
+    TestApplication::DEFAULT_VERTICAL_DPI,
+    true,
+    true);
+
+  tet_infoline("Test that partial update works well when we set visual renderer's animated properties");
+
+  const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+  Shader         shader   = Shader::New("VertexSource", "FragmentSource");
+  Geometry       geometry = CreateQuadGeometry();
+  VisualRenderer renderer = VisualRenderer::New(geometry, shader);
+
+  Actor actor = Actor::New();
+  actor.AddRenderer(renderer);
+  actor[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT;
+  actor[Actor::Property::POSITION]     = Vector3(64.0f, 64.0f, 0.0f);
+  actor[Actor::Property::SIZE]         = Vector3(64.0f, 64.0f, 0.0f);
+  actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+
+  std::vector<Rect<int>> damagedRects;
+
+  // Actor added, damaged rect is added size of actor
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+  // Aligned by 16
+  Rect<int> clippingRect = Rect<int>(64, 672, 80, 80); // in screen coordinates, includes 3 last frames updates
+  DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+  DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Set clippingRect as full surface now. TODO : Set valid rect if we can.
+  clippingRect = TestApplication::DEFAULT_SURFACE_RECT;
+
+  Property::Index index = VisualRenderer::Property::TRANSFORM_SIZE;
+  renderer.SetProperty(index, Vector2(2.0f, 0.5f));
+
+  // Now current actor show as 128x32 rectangle, with center position (96, 96).
+  // So, rectangle's top left position is (32, 80), and bottom right position is (160, 112).
+  // NOTE : VisualTransform's anchor point is not relative with actor's anchor point
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  // Note, this damagedRect is combine of previous rect and current rect
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(32, 672, 144, 80), damagedRects[0], TEST_LOCATION);
+
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::BLUE);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+  // Aligned by 16
+  // Note, this damagedRect don't contain previous rect now.
+  // Current rectangle's top left position is (32, 80), and bottom right position is (160, 112).
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(32, 688, 144, 48), damagedRects[0], TEST_LOCATION);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // 3 frame spended after change actor property. Ensure the damaged rect is empty
+  DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector2>(index), Vector2(2.0f, 0.5f), 0.001f, TEST_LOCATION);
+
+  // Make flickered animation from Vector2(2.0f, 0.5f) --> Vector2(1.0f, 1.0f) --> Vector2(0.5f, 2.0f)
+  // After finish the animation,actor show as 32x128 rectangle, with center position (96, 96).
+  // So, rectangle's top left position is (80, 32), and bottom right position is (112, 160).
+  Animation animation = Animation::New(1.0f);
+  KeyFrames keyFrames = KeyFrames::New();
+  keyFrames.Add(0.0f, Vector2(2.0f, 0.5f));
+  keyFrames.Add(0.299f, Vector2(2.0f, 0.5f));
+  keyFrames.Add(0.301f, Vector2(1.0f, 1.0f));
+  keyFrames.Add(0.699f, Vector2(1.0f, 1.0f));
+  keyFrames.Add(0.701f, Vector2(0.5f, 2.0f));
+  keyFrames.Add(1.0f, Vector2(0.5f, 2.0f));
+  animation.AnimateBetween(Property(renderer, index), keyFrames);
+  animation.Play();
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(200, nullptr, damagedRects); // 200 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(index), Vector2(2.0f, 0.5f), TEST_LOCATION);
+
+  // 302 ~ 600. TransformSize become Vector2(1.0f, 1.0f)
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(102, nullptr, damagedRects); // 302 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(index), Vector2(1.0f, 1.0f), TEST_LOCATION);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 318 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::GREEN);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 334 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 350 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(64, 672, 80, 80), damagedRects[0], TEST_LOCATION);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(250, nullptr, damagedRects); // 600 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // 702 ~ 1000. TransformSize become Vector2(0.5f, 2.0f)
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(102, nullptr, damagedRects); // 702 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(renderer.GetCurrentProperty<Vector2>(index), Vector2(0.5f, 2.0f), TEST_LOCATION);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::GREEN);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 718 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::BLUE);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 734 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Update dummy property to damangeRect buffer aging
+  actor.SetProperty(Actor::Property::COLOR, Color::RED);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(16, nullptr, damagedRects); // 750 ms
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+  // Aligned by 16
+  DALI_TEST_EQUALS<Rect<int>>(Rect<int>(80, 640, 48, 144), damagedRects[0], TEST_LOCATION);
+
+  application.SendNotification();
+  damagedRects.clear();
+  application.PreRenderWithPartialUpdate(52, nullptr, damagedRects); // 1002 ms. animation finished.
+  application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+  // Check finished value bake.
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector2>(index), Vector2(0.5f, 2.0f), TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index 781ffff..c9ba8b3 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_KEY_FRAME_CHANNEL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,7 +54,9 @@ struct KeyFrameChannel
     }
     else
     {
-      auto end   = std::find_if(mValues.begin(), mValues.end(), [=](const auto& element) { return element.GetProgress() > progress; });
+      // Find lowest element s.t. progress is greater than progress.
+      // So start->GetProgress() <= progress < end->GetProgress() is satisfied.
+      auto end   = std::lower_bound(mValues.begin(), mValues.end(), progress, [](const auto& element, const float& progress) { return element.GetProgress() <= progress; });
       auto start = end - 1;
 
       const bool validInterval = (end != mValues.end()) && (start->GetProgress() <= progress);
diff --git a/dali/internal/event/rendering/decorated-visual-renderer-impl.cpp b/dali/internal/event/rendering/decorated-visual-renderer-impl.cpp
new file mode 100644 (file)
index 0000000..3808a54
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/event/rendering/decorated-visual-renderer-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
+#include <dali/internal/event/common/property-input-impl.h>
+#include <dali/internal/update/manager/update-manager.h>
+#include <dali/internal/update/rendering/scene-graph-renderer.h>
+#include <dali/public-api/object/type-registry.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace
+{
+/**
+ * Properties: |name                              |type     |writable|animatable|constraint-input|enum for index-checking|
+ */
+DALI_PROPERTY_TABLE_BEGIN
+DALI_PROPERTY("cornerRadius", VECTOR4, true, true, true, Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS)
+DALI_PROPERTY("cornerRadiusPolicy", FLOAT, true, false, true, Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY)
+DALI_PROPERTY("borderlineWidth", FLOAT, true, true, true, Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH)
+DALI_PROPERTY("borderlineColor", VECTOR4, true, true, true, Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR)
+DALI_PROPERTY("borderlineOffset", FLOAT, true, true, true, Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET)
+DALI_PROPERTY("blurRadius", FLOAT, true, true, true, Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS)
+DALI_PROPERTY_TABLE_END(Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS, DecoratedVisualRendererDefaultProperties)
+
+BaseHandle Create()
+{
+  return Dali::BaseHandle();
+}
+
+TypeRegistration mType(typeid(Dali::DecoratedVisualRenderer), typeid(Dali::VisualRenderer), Create, DecoratedVisualRendererDefaultProperties);
+
+} // unnamed namespace
+
+DecoratedVisualRendererPtr DecoratedVisualRenderer::New()
+{
+  // create scene object first so it's guaranteed to exist for the event side
+  auto sceneObject = SceneGraph::Renderer::New();
+
+  auto animatableVisualProperties          = new AnimatableVisualProperties();
+  auto animatableDecoratedVisualProperties = new AnimatableDecoratedVisualProperties();
+
+  // Append extended properties as AnimatableDecoratedVisualProperties.
+  animatableVisualProperties->mExtendedProperties               = animatableDecoratedVisualProperties;
+  animatableVisualProperties->mExtendedPropertiesDeleteFunction = AnimatableDecoratedVisualProperties::DeleteFunction;
+
+  sceneObject->SetVisualProperties(animatableVisualProperties);
+
+  OwnerPointer<SceneGraph::Renderer> transferOwnership(sceneObject);
+  // pass the pointer to base for message passing
+  DecoratedVisualRendererPtr rendererPtr(new DecoratedVisualRenderer(sceneObject));
+
+  rendererPtr->AddUniformMappings(); // Ensure properties are mapped to uniforms
+
+  // transfer scene object ownership to update manager
+  EventThreadServices&       eventThreadServices = rendererPtr->GetEventThreadServices();
+  SceneGraph::UpdateManager& updateManager       = eventThreadServices.GetUpdateManager();
+  AddRendererMessage(updateManager, transferOwnership);
+
+  eventThreadServices.RegisterObject(rendererPtr.Get());
+  return rendererPtr;
+}
+
+DecoratedVisualRenderer::DecoratedVisualRenderer(const SceneGraph::Renderer* sceneObject)
+: VisualRenderer(sceneObject),
+  mDecoratedPropertyCache(),
+  mAddUniformFlag(0u)
+{
+}
+
+DecoratedVisualRenderer::~DecoratedVisualRenderer()
+{
+  // The scene object will be deleted by ~VisualRenderer
+}
+
+void DecoratedVisualRenderer::SetDefaultProperty(Property::Index        index,
+                                                 const Property::Value& propertyValue)
+{
+  if(index < Dali::DecoratedVisualRenderer::Property::DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX)
+  {
+    VisualRenderer::SetDefaultProperty(index, propertyValue);
+  }
+  else
+  {
+    switch(index)
+    {
+      case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS:
+      {
+        if(propertyValue.Get(mDecoratedPropertyCache.mCornerRadius))
+        {
+          const SceneGraph::Renderer& sceneObject      = GetVisualRendererSceneObject();
+          auto                        visualProperties = sceneObject.GetVisualProperties();
+
+          if(visualProperties)
+          {
+            auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+            if(decoratedVisualProperties)
+            {
+              BakeMessage<Vector4>(GetEventThreadServices(), decoratedVisualProperties->mCornerRadius, mDecoratedPropertyCache.mCornerRadius);
+            }
+          }
+        }
+        break;
+      }
+
+      case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY:
+      {
+        if(propertyValue.Get(mDecoratedPropertyCache.mCornerRadiusPolicy))
+        {
+          const SceneGraph::Renderer& sceneObject      = GetVisualRendererSceneObject();
+          auto                        visualProperties = sceneObject.GetVisualProperties();
+
+          if(visualProperties)
+          {
+            auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+            if(decoratedVisualProperties)
+            {
+              BakeMessage<float>(GetEventThreadServices(), decoratedVisualProperties->mCornerRadiusPolicy, mDecoratedPropertyCache.mCornerRadiusPolicy);
+            }
+          }
+        }
+        break;
+      }
+
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH:
+      {
+        if(propertyValue.Get(mDecoratedPropertyCache.mBorderlineWidth))
+        {
+          const SceneGraph::Renderer& sceneObject      = GetVisualRendererSceneObject();
+          auto                        visualProperties = sceneObject.GetVisualProperties();
+
+          if(visualProperties)
+          {
+            auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+            if(decoratedVisualProperties)
+            {
+              BakeMessage<float>(GetEventThreadServices(), decoratedVisualProperties->mBorderlineWidth, mDecoratedPropertyCache.mBorderlineWidth);
+            }
+          }
+        }
+        break;
+      }
+
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR:
+      {
+        if(propertyValue.Get(mDecoratedPropertyCache.mBorderlineColor))
+        {
+          const SceneGraph::Renderer& sceneObject      = GetVisualRendererSceneObject();
+          auto                        visualProperties = sceneObject.GetVisualProperties();
+
+          if(visualProperties)
+          {
+            auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+            if(decoratedVisualProperties)
+            {
+              BakeMessage<Vector4>(GetEventThreadServices(), decoratedVisualProperties->mBorderlineColor, mDecoratedPropertyCache.mBorderlineColor);
+            }
+          }
+        }
+        break;
+      }
+
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET:
+      {
+        if(propertyValue.Get(mDecoratedPropertyCache.mBorderlineOffset))
+        {
+          const SceneGraph::Renderer& sceneObject      = GetVisualRendererSceneObject();
+          auto                        visualProperties = sceneObject.GetVisualProperties();
+
+          if(visualProperties)
+          {
+            auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+            if(decoratedVisualProperties)
+            {
+              BakeMessage<float>(GetEventThreadServices(), decoratedVisualProperties->mBorderlineOffset, mDecoratedPropertyCache.mBorderlineOffset);
+            }
+          }
+        }
+        break;
+      }
+
+      case Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS:
+      {
+        if(propertyValue.Get(mDecoratedPropertyCache.mBlurRadius))
+        {
+          const SceneGraph::Renderer& sceneObject      = GetVisualRendererSceneObject();
+          auto                        visualProperties = sceneObject.GetVisualProperties();
+
+          if(visualProperties)
+          {
+            auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+            if(decoratedVisualProperties)
+            {
+              BakeMessage<float>(GetEventThreadServices(), decoratedVisualProperties->mBlurRadius, mDecoratedPropertyCache.mBlurRadius);
+            }
+          }
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Value DecoratedVisualRenderer::GetDefaultProperty(Property::Index index) const
+{
+  Property::Value value;
+
+  if(index < Dali::DecoratedVisualRenderer::Property::DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX)
+  {
+    value = VisualRenderer::GetDefaultProperty(index);
+  }
+  else
+  {
+    switch(index)
+    {
+      case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS:
+      {
+        value = mDecoratedPropertyCache.mCornerRadius;
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY:
+      {
+        value = mDecoratedPropertyCache.mCornerRadiusPolicy;
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH:
+      {
+        value = mDecoratedPropertyCache.mBorderlineWidth;
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR:
+      {
+        value = mDecoratedPropertyCache.mBorderlineColor;
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET:
+      {
+        value = mDecoratedPropertyCache.mBorderlineOffset;
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS:
+      {
+        value = mDecoratedPropertyCache.mBlurRadius;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+Property::Value DecoratedVisualRenderer::GetDefaultPropertyCurrentValue(Property::Index index) const
+{
+  Property::Value value;
+
+  if(index < Dali::DecoratedVisualRenderer::Property::DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX)
+  {
+    value = VisualRenderer::GetDefaultPropertyCurrentValue(index);
+  }
+  else
+  {
+    const SceneGraph::Renderer& sceneObject = GetVisualRendererSceneObject();
+
+    switch(index)
+    {
+      case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS:
+      {
+        auto visualProperties = sceneObject.GetVisualProperties();
+        if(visualProperties)
+        {
+          auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+          if(decoratedVisualProperties)
+          {
+            value = decoratedVisualProperties->mCornerRadius[GetEventThreadServices().GetEventBufferIndex()];
+          }
+        }
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY:
+      {
+        auto visualProperties = sceneObject.GetVisualProperties();
+        if(visualProperties)
+        {
+          auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+          if(decoratedVisualProperties)
+          {
+            value = decoratedVisualProperties->mCornerRadiusPolicy[GetEventThreadServices().GetEventBufferIndex()];
+          }
+        }
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH:
+      {
+        auto visualProperties = sceneObject.GetVisualProperties();
+        if(visualProperties)
+        {
+          auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+          if(decoratedVisualProperties)
+          {
+            value = decoratedVisualProperties->mBorderlineWidth[GetEventThreadServices().GetEventBufferIndex()];
+          }
+        }
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR:
+      {
+        auto visualProperties = sceneObject.GetVisualProperties();
+        if(visualProperties)
+        {
+          auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+          if(decoratedVisualProperties)
+          {
+            value = decoratedVisualProperties->mBorderlineColor[GetEventThreadServices().GetEventBufferIndex()];
+          }
+        }
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET:
+      {
+        auto visualProperties = sceneObject.GetVisualProperties();
+        if(visualProperties)
+        {
+          auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+          if(decoratedVisualProperties)
+          {
+            value = decoratedVisualProperties->mBorderlineOffset[GetEventThreadServices().GetEventBufferIndex()];
+          }
+        }
+        break;
+      }
+      case Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS:
+      {
+        auto visualProperties = sceneObject.GetVisualProperties();
+        if(visualProperties)
+        {
+          auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+          if(decoratedVisualProperties)
+          {
+            value = decoratedVisualProperties->mBlurRadius[GetEventThreadServices().GetEventBufferIndex()];
+          }
+        }
+        break;
+      }
+    }
+  }
+  return value;
+}
+
+void DecoratedVisualRenderer::OnNotifyDefaultPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
+{
+  if(index < Dali::DecoratedVisualRenderer::Property::DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX)
+  {
+    VisualRenderer::OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
+  }
+  else
+  {
+    switch(animationType)
+    {
+      case Animation::TO:
+      case Animation::BETWEEN:
+      {
+        switch(index)
+        {
+          case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS:
+          {
+            value.Get(mDecoratedPropertyCache.mCornerRadius);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH:
+          {
+            value.Get(mDecoratedPropertyCache.mBorderlineWidth);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR:
+          {
+            value.Get(mDecoratedPropertyCache.mBorderlineColor);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET:
+          {
+            value.Get(mDecoratedPropertyCache.mBorderlineOffset);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS:
+          {
+            value.Get(mDecoratedPropertyCache.mBlurRadius);
+            break;
+          }
+        }
+        break;
+      }
+
+      case Animation::BY:
+      {
+        switch(index)
+        {
+          case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS:
+          {
+            AdjustValue<Vector4>(mDecoratedPropertyCache.mCornerRadius, value);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH:
+          {
+            AdjustValue<float>(mDecoratedPropertyCache.mBorderlineWidth, value);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR:
+          {
+            AdjustValue<Vector4>(mDecoratedPropertyCache.mBorderlineColor, value);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET:
+          {
+            AdjustValue<float>(mDecoratedPropertyCache.mBorderlineOffset, value);
+            break;
+          }
+          case Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS:
+          {
+            AdjustValue<float>(mDecoratedPropertyCache.mBlurRadius, value);
+            break;
+          }
+        }
+        break;
+      }
+    }
+  }
+}
+
+const SceneGraph::PropertyBase* DecoratedVisualRenderer::GetSceneObjectAnimatableProperty(Property::Index index) const
+{
+  const SceneGraph::PropertyBase* property = nullptr;
+
+  switch(index)
+  {
+    case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS:
+    {
+      auto visualProperties = GetVisualRendererSceneObject().GetVisualProperties();
+      if(visualProperties)
+      {
+        auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+        if(decoratedVisualProperties)
+        {
+          property = &decoratedVisualProperties->mCornerRadius;
+        }
+      }
+      break;
+    }
+    case Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH:
+    {
+      auto visualProperties = GetVisualRendererSceneObject().GetVisualProperties();
+      if(visualProperties)
+      {
+        auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+        if(decoratedVisualProperties)
+        {
+          property = &decoratedVisualProperties->mBorderlineWidth;
+        }
+      }
+      break;
+    }
+    case Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR:
+    {
+      auto visualProperties = GetVisualRendererSceneObject().GetVisualProperties();
+      if(visualProperties)
+      {
+        auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+        if(decoratedVisualProperties)
+        {
+          property = &decoratedVisualProperties->mBorderlineColor;
+        }
+      }
+      break;
+    }
+    case Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET:
+    {
+      auto visualProperties = GetVisualRendererSceneObject().GetVisualProperties();
+      if(visualProperties)
+      {
+        auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+        if(decoratedVisualProperties)
+        {
+          property = &decoratedVisualProperties->mBorderlineOffset;
+        }
+      }
+      break;
+    }
+    case Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS:
+    {
+      auto visualProperties = GetVisualRendererSceneObject().GetVisualProperties();
+      if(visualProperties)
+      {
+        auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+        if(decoratedVisualProperties)
+        {
+          property = &decoratedVisualProperties->mBlurRadius;
+        }
+      }
+      break;
+    }
+  }
+
+  if(!property)
+  {
+    // not our property, ask base
+    property = VisualRenderer::GetSceneObjectAnimatableProperty(index);
+  }
+
+  return property;
+}
+
+const PropertyInputImpl* DecoratedVisualRenderer::GetSceneObjectInputProperty(Property::Index index) const
+{
+  if(index < Dali::DecoratedVisualRenderer::Property::DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX)
+  {
+    return VisualRenderer::GetSceneObjectInputProperty(index);
+  }
+  switch(index)
+  {
+    case Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY:
+    {
+      auto visualProperties = GetVisualRendererSceneObject().GetVisualProperties();
+      if(visualProperties)
+      {
+        auto decoratedVisualProperties = static_cast<AnimatableDecoratedVisualProperties*>(visualProperties->mExtendedProperties);
+        if(decoratedVisualProperties)
+        {
+          return &decoratedVisualProperties->mCornerRadiusPolicy;
+        }
+      }
+      break;
+    }
+    default:
+    {
+      return GetSceneObjectAnimatableProperty(index);
+    }
+  }
+  return nullptr;
+}
+
+void DecoratedVisualRenderer::RegisterCornerRadiusUniform()
+{
+  AddUniformFlag(DECORATED_VISUAL_RENDERER_USE_CORNER_RADIUS);
+}
+
+void DecoratedVisualRenderer::RegisterBorderlineUniform()
+{
+  AddUniformFlag(DECORATED_VISUAL_RENDERER_USE_BORDERLINE);
+}
+
+void DecoratedVisualRenderer::RegisterBlurRadiusUniform()
+{
+  AddUniformFlag(DECORATED_VISUAL_RENDERER_USE_BLUR_RADIUS);
+}
+
+void DecoratedVisualRenderer::AddUniformFlag(uint8_t newAddFlag)
+{
+  const uint8_t diffUniformFlag = (~mAddUniformFlag) & newAddFlag;
+  if(diffUniformFlag)
+  {
+    if(diffUniformFlag & DECORATED_VISUAL_RENDERER_USE_CORNER_RADIUS)
+    {
+      AddUniformMapping(Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS, ConstString("cornerRadius"));
+      AddUniformMapping(Dali::DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, ConstString("cornerRadiusPolicy"));
+    }
+    if(diffUniformFlag & DECORATED_VISUAL_RENDERER_USE_BORDERLINE)
+    {
+      AddUniformMapping(Dali::DecoratedVisualRenderer::Property::BORDERLINE_WIDTH, ConstString("borderlineWidth"));
+      AddUniformMapping(Dali::DecoratedVisualRenderer::Property::BORDERLINE_COLOR, ConstString("borderlineColor"));
+      AddUniformMapping(Dali::DecoratedVisualRenderer::Property::BORDERLINE_OFFSET, ConstString("borderlineOffset"));
+    }
+    if(diffUniformFlag & DECORATED_VISUAL_RENDERER_USE_BLUR_RADIUS)
+    {
+      AddUniformMapping(Dali::DecoratedVisualRenderer::Property::BLUR_RADIUS, ConstString("blurRadius"));
+    }
+
+    // Note. Let we don't remove UniformMapping due to the performane issue.
+    mAddUniformFlag |= newAddFlag;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/event/rendering/decorated-visual-renderer-impl.h b/dali/internal/event/rendering/decorated-visual-renderer-impl.h
new file mode 100644 (file)
index 0000000..b8405fe
--- /dev/null
@@ -0,0 +1,214 @@
+#ifndef DALI_INTERNAL_DECORATED_VISUAL_RENDERER_H
+#define DALI_INTERNAL_DECORATED_VISUAL_RENDERER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/rendering/visual-renderer-impl.h>  // Dali::Internal::VisualRenderer
+#include <dali/public-api/rendering/decorated-visual-renderer.h> // Dali::DecoratedVisualRenderer
+
+namespace Dali
+{
+namespace Internal
+{
+namespace SceneGraph
+{
+class Renderer;
+}
+
+class DecoratedVisualRenderer;
+using DecoratedVisualRendererPtr = IntrusivePtr<DecoratedVisualRenderer>;
+
+/**
+ * DecoratedVisualRenderer is a VisualRenderer that has additional default properties for toolkit
+ */
+class DecoratedVisualRenderer : public VisualRenderer
+{
+public:
+  /**
+   * Create a new DecoratedVisualRenderer.
+   * @return A smart-pointer to the newly allocated DecoratedVisualRenderer.
+   */
+  static DecoratedVisualRendererPtr New();
+
+public: // Default property extensions from Object
+  /**
+   * @copydoc Dali::Internal::Object::SetDefaultProperty()
+   */
+  void SetDefaultProperty(Property::Index index, const Property::Value& propertyValue) override;
+
+  /**
+   * @copydoc Dali::Internal::Object::GetDefaultProperty()
+   */
+  Property::Value GetDefaultProperty(Property::Index index) const override;
+
+  /**
+   * @copydoc Dali::Internal::Object::GetDefaultPropertyCurrentValue()
+   */
+  Property::Value GetDefaultPropertyCurrentValue(Property::Index index) const override;
+
+  /**
+    * @copydoc Dali::Internal::Object::OnNotifyDefaultPropertyAnimation()
+    */
+  void OnNotifyDefaultPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType) override;
+
+  /**
+   * @copydoc Dali::Internal::Object::GetSceneObjectAnimatableProperty()
+   */
+  const SceneGraph::PropertyBase* GetSceneObjectAnimatableProperty(Property::Index index) const override;
+
+  /**
+   * @copydoc Dali::Internal::Object::GetSceneObjectInputProperty()
+   */
+  const PropertyInputImpl* GetSceneObjectInputProperty(Property::Index index) const override;
+
+public:
+  /**
+   * @copydoc Dali::DecoratedVisualRenderer::RegisterCornerRadiusUniform()
+   */
+  void RegisterCornerRadiusUniform();
+
+  /**
+   * @copydoc Dali::DecoratedVisualRenderer::RegisterBorderlineUniform()
+   */
+  void RegisterBorderlineUniform();
+
+  /**
+   * @copydoc Dali::DecoratedVisualRenderer::RegisterBlurRadiusUniform()
+   */
+  void RegisterBlurRadiusUniform();
+
+protected: // implementation
+  /**
+   * @brief Constructor.
+   *
+   * @param sceneObject the scene graph renderer
+   */
+  DecoratedVisualRenderer(const SceneGraph::Renderer* sceneObject);
+
+  /**
+   * @brief Retrieves the current value of a default property from the scene-graph.
+   * @param[in]  index  The index of the property
+   * @param[out] value  Is set with the current scene-graph value of the property
+   * @return True if value set, false otherwise.
+   */
+  bool GetCurrentPropertyValue(Property::Index index, Property::Value& value) const;
+
+  /**
+   * @brief Add the uniforms for DecoratedVisualRendererUseType.
+   * If that flag didn't appended yet, It will add the uniforms map
+   *
+   * @param[in] newFlag one of DecoratedVisualRendererUseType
+   */
+  void AddUniformFlag(uint8_t newAddFlag);
+
+protected:
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  ~DecoratedVisualRenderer() override;
+
+private:
+  DecoratedVisualRenderer(const DecoratedVisualRenderer&) = delete;
+  DecoratedVisualRenderer& operator=(const DecoratedVisualRenderer&) = delete;
+
+public:
+  enum DecoratedVisualRendererUseType
+  {
+    DECORATED_VISUAL_RENDERER_USE_CORNER_RADIUS = 1,
+    DECORATED_VISUAL_RENDERER_USE_BORDERLINE    = 2,
+    DECORATED_VISUAL_RENDERER_USE_BLUR_RADIUS   = 4,
+  };
+
+  struct DecoratedVisualPropertyCache
+  {
+    Vector4 mCornerRadius{Vector4::ZERO};
+    float   mCornerRadiusPolicy{1.0f};
+    float   mBorderlineWidth{0.0f};
+    Vector4 mBorderlineColor{Color::BLACK};
+    float   mBorderlineOffset{0.0f};
+    float   mBlurRadius{0.0f};
+  };
+
+  struct AnimatableDecoratedVisualProperties
+  {
+    AnimatableDecoratedVisualProperties()
+    : mCornerRadius(Vector4::ZERO),
+      mCornerRadiusPolicy(1.0f),
+      mBorderlineWidth(0.0f),
+      mBorderlineColor(Color::BLACK),
+      mBorderlineOffset(0.0f),
+      mBlurRadius(0.0f),
+      mExtendedPropertiesDeleteFunction(nullptr)
+    {
+    }
+    ~AnimatableDecoratedVisualProperties()
+    {
+      if(mExtendedProperties && mExtendedPropertiesDeleteFunction)
+      {
+        mExtendedPropertiesDeleteFunction(mExtendedProperties);
+      }
+    }
+
+    // Delete function of AnimatableDecoratedVisualProperties* converted as void*
+    constexpr static void DeleteFunction(void* data)
+    {
+      delete static_cast<AnimatableDecoratedVisualProperties*>(data);
+    }
+
+    SceneGraph::AnimatableProperty<Vector4> mCornerRadius;
+    SceneGraph::AnimatableProperty<float>   mCornerRadiusPolicy;
+    SceneGraph::AnimatableProperty<float>   mBorderlineWidth;
+    SceneGraph::AnimatableProperty<Vector4> mBorderlineColor;
+    SceneGraph::AnimatableProperty<float>   mBorderlineOffset;
+    SceneGraph::AnimatableProperty<float>   mBlurRadius;
+
+    void* mExtendedProperties{nullptr};                        // Enable derived class to extend properties further
+    void (*mExtendedPropertiesDeleteFunction)(void*){nullptr}; // Derived class's custom delete functor
+  };
+
+private:
+  DecoratedVisualPropertyCache mDecoratedPropertyCache;
+
+  uint8_t mAddUniformFlag : 4;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+inline Internal::DecoratedVisualRenderer& GetImplementation(Dali::DecoratedVisualRenderer& handle)
+{
+  DALI_ASSERT_ALWAYS(handle && "DecoratedVisualRenderer handle is empty");
+
+  BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<Internal::DecoratedVisualRenderer&>(object);
+}
+
+inline const Internal::DecoratedVisualRenderer& GetImplementation(const Dali::DecoratedVisualRenderer& handle)
+{
+  DALI_ASSERT_ALWAYS(handle && "DecoratedVisualRenderer handle is empty");
+
+  const BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<const Internal::DecoratedVisualRenderer&>(object);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_DECORATED_VISUAL_RENDERER_H
index c90448c..b7a758c 100644 (file)
@@ -92,14 +92,7 @@ VisualRenderer::VisualRenderer(const SceneGraph::Renderer* sceneObject)
 
 VisualRenderer::~VisualRenderer()
 {
-  if(EventThreadServices::IsCoreRunning())
-  {
-    EventThreadServices&       eventThreadServices = GetEventThreadServices();
-    SceneGraph::UpdateManager& updateManager       = eventThreadServices.GetUpdateManager();
-    RemoveRendererMessage(updateManager, GetVisualRendererSceneObject());
-
-    eventThreadServices.UnregisterObject(this);
-  }
+  // The scene object will be deleted by ~Renderer
 }
 
 const SceneGraph::Renderer& VisualRenderer::GetVisualRendererSceneObject() const
index 8c402a8..b7af4d7 100644 (file)
@@ -85,7 +85,7 @@ public: // Default property extensions from Object
    */
   const PropertyInputImpl* GetSceneObjectInputProperty(Property::Index index) const override;
 
-private: // implementation
+protected: // implementation
   /**
    * @brief Constructor.
    *
@@ -101,6 +101,11 @@ private: // implementation
    */
   bool GetCurrentPropertyValue(Property::Index index, Property::Value& value) const;
 
+  /**
+   * @brief Ensure that properties are mapped to uniforms
+   */
+  void AddUniformMappings();
+
 protected:
   /**
    * A reference counted object may only be deleted by calling Unreference()
@@ -111,16 +116,11 @@ private:
   VisualRenderer(const VisualRenderer&) = delete;
   VisualRenderer& operator=(const VisualRenderer&) = delete;
 
-  /**
-   * @brief Ensure that properties are mapped to uniforms
-   */
-  void AddUniformMappings();
-
 public:
   struct VisualPropertyCache
   {
     Vector2 mTransformOffset{Vector2::ZERO};
-    Vector2 mTransformSize{Vector2::ZERO};
+    Vector2 mTransformSize{Vector2::ONE};
     Vector2 mTransformOrigin{Vector2::ZERO};
     Vector2 mTransformAnchorPoint{Vector2::ZERO};
     Vector4 mTransformOffsetSizeMode{Vector2::ZERO};
@@ -133,14 +133,23 @@ public:
   {
     AnimatableVisualProperties()
     : mTransformOffset(Vector2::ZERO),
-      mTransformSize(Vector2::ZERO),
+      mTransformSize(Vector2::ONE),
       mTransformOrigin(Vector2::ZERO),
       mTransformAnchorPoint(Vector2::ZERO),
       mTransformOffsetSizeMode(Vector4::ZERO),
       mExtraSize(Vector2::ZERO),
       mMixColor(Vector3::ONE),
-      mPreMultipliedAlpha(0.0f)
+      mPreMultipliedAlpha(0.0f),
+      mExtendedPropertiesDeleteFunction(nullptr)
+    {
+    }
+
+    ~AnimatableVisualProperties()
     {
+      if(mExtendedProperties && mExtendedPropertiesDeleteFunction)
+      {
+        mExtendedPropertiesDeleteFunction(mExtendedProperties);
+      }
     }
 
     SceneGraph::AnimatableProperty<Vector2> mTransformOffset;
@@ -152,7 +161,8 @@ public:
     SceneGraph::AnimatableProperty<Vector3> mMixColor;
     SceneGraph::AnimatableProperty<float>   mPreMultipliedAlpha;
 
-    void* mExtendedProperties{nullptr}; // Enable derived class to extend properties further
+    void* mExtendedProperties{nullptr};                        // Enable derived class to extend properties further
+    void (*mExtendedPropertiesDeleteFunction)(void*){nullptr}; // Derived class's custom delete functor
   };
 
 private:
@@ -182,4 +192,4 @@ inline const Internal::VisualRenderer& GetImplementation(const Dali::VisualRende
 
 } // namespace Dali
 
-#endif // DALI_INTERNAL_RENDERER_H
+#endif // DALI_INTERNAL_VISUAL_RENDERER_H
index f1dcd94..884868d 100644 (file)
@@ -91,6 +91,7 @@ SET( internal_src_files
   ${internal_src_dir}/event/images/pixel-data-impl.cpp
   ${internal_src_dir}/event/render-tasks/render-task-impl.cpp
   ${internal_src_dir}/event/render-tasks/render-task-list-impl.cpp
+  ${internal_src_dir}/event/rendering/decorated-visual-renderer-impl.cpp
   ${internal_src_dir}/event/rendering/frame-buffer-impl.cpp
   ${internal_src_dir}/event/rendering/geometry-impl.cpp
   ${internal_src_dir}/event/rendering/texture-impl.cpp
index dd6c207..b481a8a 100644 (file)
@@ -566,18 +566,24 @@ int Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::No
   // Usual case is to only have 1 node, however we do allow multiple nodes to reuse the same
   // renderer, so we have to cache uniform map per render item (node / renderer pair).
 
-  const void* nodePtr = static_cast<const void*>(&node);
-  auto        iter    = std::find_if(mNodeIndexMap.begin(), mNodeIndexMap.end(), [nodePtr](RenderItemLookup& element) { return element.node == nodePtr; });
+  // Specially, if node don't have uniformMap, we mark nodePtr as nullptr.
+  // So, all nodes without uniformMap will share same UniformIndexMap, contains only render data providers.
+  const auto nodePtr = uniformMapNode.Count() ? &node : nullptr;
+
+  const auto nodeChangeCounter          = nodePtr ? uniformMapNode.GetChangeCounter() : 0;
+  const auto renderItemMapChangeCounter = uniformMap.GetChangeCounter();
+
+  auto iter = std::find_if(mNodeIndexMap.begin(), mNodeIndexMap.end(), [nodePtr](RenderItemLookup& element) { return element.node == nodePtr; });
 
   int renderItemMapIndex;
   if(iter == mNodeIndexMap.end())
   {
     renderItemMapIndex = mUniformIndexMaps.size();
     RenderItemLookup renderItemLookup;
-    renderItemLookup.node                       = &node;
+    renderItemLookup.node                       = nodePtr;
     renderItemLookup.index                      = renderItemMapIndex;
-    renderItemLookup.nodeChangeCounter          = uniformMapNode.GetChangeCounter();
-    renderItemLookup.renderItemMapChangeCounter = uniformMap.GetChangeCounter();
+    renderItemLookup.nodeChangeCounter          = nodeChangeCounter;
+    renderItemLookup.renderItemMapChangeCounter = renderItemMapChangeCounter;
     mNodeIndexMap.emplace_back(renderItemLookup);
 
     updateMaps = true;
@@ -587,12 +593,12 @@ int Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::No
   {
     renderItemMapIndex = iter->index;
 
-    updateMaps = (uniformMapNode.GetChangeCounter() != iter->nodeChangeCounter) ||
-                 (uniformMap.GetChangeCounter() != iter->renderItemMapChangeCounter) ||
+    updateMaps = (nodeChangeCounter != iter->nodeChangeCounter) ||
+                 (renderItemMapChangeCounter != iter->renderItemMapChangeCounter) ||
                  (mUniformIndexMaps[renderItemMapIndex].size() == 0);
 
-    iter->nodeChangeCounter          = uniformMapNode.GetChangeCounter();
-    iter->renderItemMapChangeCounter = uniformMap.GetChangeCounter();
+    iter->nodeChangeCounter          = nodeChangeCounter;
+    iter->renderItemMapChangeCounter = renderItemMapChangeCounter;
   }
 
   if(updateMaps || mShaderChanged)
index 4156671..1523aa4 100644 (file)
@@ -566,7 +566,7 @@ private:
   /** Struct to map node to index into mNodeMapCounters and mUniformIndexMaps */
   struct RenderItemLookup
   {
-    const SceneGraph::NodeDataProvider* node{nullptr}; ///<Node key
+    const SceneGraph::NodeDataProvider* node{nullptr}; ///<Node key. It can be nullptr if this NodeIndex don't need node uniform
 
     std::size_t index{0};                       ///<Index into mUniformIndexMap
     std::size_t nodeChangeCounter{0};           ///<The last known change counter for this node's uniform map
index 947253c..0a889a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -95,8 +95,8 @@ void DiscardQueue::Clear(BufferIndex updateBufferIndex)
 {
   // Destroy some discarded objects; these should no longer own any GL resources
   mNodeQueue[updateBufferIndex].Clear();
-  mShaderQueue[updateBufferIndex].Clear();
   mRendererQueue[updateBufferIndex].Clear();
+  mShaderQueue[updateBufferIndex].Clear();
   mCameraQueue[updateBufferIndex].Clear();
   mSceneQueue[updateBufferIndex].Clear();
 }
index d021083..744d674 100644 (file)
@@ -143,8 +143,10 @@ bool CompareItems3DWithClipping(const RenderInstructionProcessor::SortAttributes
  * @param[in,out] nodeWorldMatrix The world matrix of the node
  * @param[in,out] nodeSize The size of the node
  * @param[in,out] nodeUpdateSize The update size of the node
+ *
+ * @return True if node use it's own UpdateSizeHint, or z transform occured. False if we use nodeUpdateSize equal with nodeSize.
  */
-inline void SetNodeUpdateSize(Node* node, bool isLayer3d, Matrix& nodeWorldMatrix, Vector3& nodeSize, Vector3& nodeUpdateSize)
+inline bool SetNodeUpdateSize(Node* node, bool isLayer3d, Matrix& nodeWorldMatrix, Vector3& nodeSize, Vector3& nodeUpdateSize)
 {
   node->GetWorldMatrixAndSize(nodeWorldMatrix, nodeSize);
 
@@ -155,11 +157,15 @@ inline void SetNodeUpdateSize(Node* node, bool isLayer3d, Matrix& nodeWorldMatri
     if(!isLayer3d && nodeWorldMatrix.GetZAxis() == Vector3(0.0f, 0.0f, 1.0f))
     {
       nodeUpdateSize = nodeSize;
+      return false;
     }
+    // Keep nodeUpdateSize as Vector3::ZERO, and return true.
+    return true;
   }
   else
   {
     nodeUpdateSize = node->GetUpdateSizeHint();
+    return true;
   }
 }
 
@@ -191,6 +197,7 @@ inline void AddRendererToRenderList(BufferIndex         updateBufferIndex,
   Vector3 nodeSize;
   Vector3 nodeUpdateSize;
   bool    nodeUpdateSizeSet(false);
+  bool    nodeUpdateSizeUseHint(false);
   Matrix  nodeModelViewMatrix(false);
   bool    nodeModelViewMatrixSet(false);
 
@@ -205,8 +212,8 @@ inline void AddRendererToRenderList(BufferIndex         updateBufferIndex,
 
     if(inside && !isLayer3d && viewportSet)
     {
-      SetNodeUpdateSize(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateSize);
-      nodeUpdateSizeSet = true;
+      nodeUpdateSizeUseHint = SetNodeUpdateSize(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateSize);
+      nodeUpdateSizeSet     = true;
 
       const Vector3& scale = node->GetWorldScale(updateBufferIndex);
       const Vector3& size  = nodeUpdateSize * scale;
@@ -280,8 +287,8 @@ inline void AddRendererToRenderList(BufferIndex         updateBufferIndex,
         item.mTextureSet = renderable.mRenderer->GetTextureSet();
         item.mDepthIndex += renderable.mRenderer->GetDepthIndex();
 
-        // Ensure collected map is up to date
-        item.mIsUpdated |= renderable.mRenderer->UpdateUniformMap();
+        // Get whether collected map is up to date
+        item.mIsUpdated |= renderable.mRenderer->UniformMapUpdated();
       }
       else
       {
@@ -292,13 +299,19 @@ inline void AddRendererToRenderList(BufferIndex         updateBufferIndex,
 
       if(!nodeUpdateSizeSet)
       {
-        SetNodeUpdateSize(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateSize);
+        nodeUpdateSizeUseHint = SetNodeUpdateSize(node, isLayer3d, nodeWorldMatrix, nodeSize, nodeUpdateSize);
       }
 
       item.mSize        = nodeSize;
       item.mUpdateSize  = nodeUpdateSize;
       item.mModelMatrix = nodeWorldMatrix;
 
+      // Apply transform informations if node doesn't have update size hint and use VisualRenderer.
+      if(!nodeUpdateSizeUseHint && renderable.mRenderer && renderable.mRenderer->GetVisualProperties())
+      {
+        item.mUpdateSize = renderable.mRenderer->CalculateVisualTransformedUpdateSize(updateBufferIndex, item.mUpdateSize);
+      }
+
       if(!nodeModelViewMatrixSet)
       {
         Matrix::Multiply(nodeModelViewMatrix, nodeWorldMatrix, viewMatrix);
index e5b96d0..879707b 100644 (file)
@@ -228,6 +228,10 @@ struct UpdateManager::Impl
     scenes.clear();
 
     delete sceneController;
+
+    // Ensure to clear renderers
+    renderers.Clear();
+    shaders.Clear();
   }
 
   /**
index a0f4b4e..0036c92 100644 (file)
@@ -21,6 +21,7 @@
 #include <dali/internal/common/blending-options.h>
 #include <dali/internal/common/internal-constants.h>
 #include <dali/internal/common/memory-pool-object-allocator.h>
+#include <dali/internal/event/rendering/decorated-visual-renderer-impl.h> // For DecoratedVisualRenderer::AnimatableDecoratedVisualProperties
 #include <dali/internal/render/data-providers/node-data-provider.h>
 #include <dali/internal/render/data-providers/render-data-provider.h>
 #include <dali/internal/render/queue/render-queue.h>
@@ -32,6 +33,8 @@
 #include <dali/internal/update/nodes/node.h>
 #include <dali/internal/update/rendering/scene-graph-texture-set.h>
 
+#include <dali/integration-api/debug.h>
+
 namespace Dali
 {
 namespace Internal
@@ -40,6 +43,10 @@ namespace SceneGraph
 {
 namespace // unnamed namespace
 {
+#ifdef DEBUG_ENABLED
+Debug::Filter* gSceneGraphRendererLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_SG_RENDERER");
+#endif
+
 //Memory pool used to allocate new renderers. Memory used by this pool will be released when shutting down DALi
 MemoryPoolObjectAllocator<Renderer> gRendererMemoryPool;
 
@@ -97,6 +104,7 @@ Renderer::Renderer()
   mRenderingBehavior(DevelRenderer::Rendering::IF_REQUIRED),
   mUpdateDecay(Renderer::Decay::INITIAL),
   mRegenerateUniformMap(false),
+  mUniformMapUpdated(false),
   mPremultipledAlphaEnabled(false),
   mOpacity(1.0f),
   mDepthIndex(0)
@@ -288,6 +296,9 @@ bool Renderer::PrepareRender(BufferIndex updateBufferIndex)
     mResendFlag = 0;
   }
 
+  // Ensure collected map is up to date
+  UpdateUniformMap();
+
   return rendererUpdated;
 }
 
@@ -645,10 +656,8 @@ Renderer::OpacityType Renderer::GetOpacityType(BufferIndex updateBufferIndex, co
   return opacityType;
 }
 
-bool Renderer::UpdateUniformMap()
+void Renderer::UpdateUniformMap()
 {
-  bool updated = false;
-
   if(mRegenerateUniformMap)
   {
     CollectedUniformMap& localMap = mCollectedUniformMap;
@@ -670,9 +679,8 @@ bool Renderer::UpdateUniformMap()
     }
     localMap.UpdateChangeCounter();
     mRegenerateUniformMap = false;
-    updated               = true;
+    mUniformMapUpdated    = true;
   }
-  return updated;
 }
 
 void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size)
@@ -693,6 +701,139 @@ const CollectedUniformMap& Renderer::GetCollectedUniformMap() const
   return mCollectedUniformMap;
 }
 
+Vector3 Renderer::CalculateVisualTransformedUpdateSize(BufferIndex updateBufferIndex, const Vector3& originalSize)
+{
+  if(mVisualProperties)
+  {
+    // TODO : We may need to get some method that visual properties changed, without hash.
+    // Or, need to call this API in PreRender side.
+
+    uint64_t hash = 0xc70f6907UL;
+
+    hash = mVisualProperties->mTransformOffset.Hash(updateBufferIndex, hash);
+    hash = mVisualProperties->mTransformOffsetSizeMode.Hash(updateBufferIndex, hash);
+    hash = mVisualProperties->mTransformSize.Hash(updateBufferIndex, hash);
+    hash = mVisualProperties->mTransformOrigin.Hash(updateBufferIndex, hash);
+    hash = mVisualProperties->mTransformAnchorPoint.Hash(updateBufferIndex, hash);
+    hash = mVisualProperties->mExtraSize.Hash(updateBufferIndex, hash);
+
+    if(mVisualPropertiesCoefficient.hash != hash)
+    {
+      mVisualPropertiesCoefficient.hash = hash;
+
+      // VisualProperty
+      const Vector2 transformOffset         = mVisualProperties->mTransformOffset.Get(updateBufferIndex);
+      const Vector4 transformOffsetSizeMode = mVisualProperties->mTransformOffsetSizeMode.Get(updateBufferIndex);
+      const Vector2 transformSize           = mVisualProperties->mTransformSize.Get(updateBufferIndex);
+      const Vector2 transformOrigin         = mVisualProperties->mTransformOrigin.Get(updateBufferIndex);
+      const Vector2 transformAnchorPoint    = mVisualProperties->mTransformAnchorPoint.Get(updateBufferIndex);
+      const Vector2 extraSize               = mVisualProperties->mExtraSize.Get(updateBufferIndex);
+
+      DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "transform size   %5.3f %5.3f\n", transformSize.x, transformSize.y);
+      DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "transform offset %5.3f %5.3f\n", transformOffset.x, transformOffset.y);
+      DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "transform origin %5.3f %5.3f\n", transformOrigin.x, transformOrigin.y);
+      DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "transform anchor %5.3f %5.3f\n", transformAnchorPoint.x, transformAnchorPoint.y);
+      DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "extra size       %5.3f %5.3f\n", extraSize.x, extraSize.y);
+
+      // const Vector2 visualSize = Vector2(Dali::Lerp(transformOffsetSizeMode.z, originalSize.x * transformSize.x, transformSize.x),
+      //                                    Dali::Lerp(transformOffsetSizeMode.w, originalSize.y * transformSize.y, transformSize.y)) +
+      //                            extraSize;
+      // const Vector2 visualOffset = Vector2(Dali::Lerp(transformOffsetSizeMode.x, originalSize.x * transformOffset.x, transformOffset.x),
+      //                                      Dali::Lerp(transformOffsetSizeMode.y, originalSize.y * transformOffset.y, transformOffset.y));
+
+      // const float decoratedBorderlineWidth = std::max((1.0f + Dali::Clamp(borderlineOffset, -1.0f, 1.0f)) * borderlineWidth, 2.0f * blurRadius);
+      // const Vector2 decoratedVisualSize    = visualSize + Vector2(decoratedBorderlineWidth, decoratedBorderlineWidth);
+
+      // Note : vertexPositoin.xy = aPosition * decoratedVisualSize
+      //                          + anchorPoint * visualSize
+      //                          + origin * uSize.xy
+      //                          + visualOffset;
+
+      // Calculate same logic of visual's vertex shader transform.
+      // minVertexPosition = -0.5f * decoratedVisualSize + transformAnchorPoint * visualSize + transformOrigin * originalSize.xy + visualOffset
+      // maxVertexPosition =  0.5f * decoratedVisualSize + transformAnchorPoint * visualSize + transformOrigin * originalSize.xy + visualOffset
+
+      // Update cached VisualTransformedUpdateSizeCoefficientCache
+
+      // Note : vertexPosition = (XA * aPosition + XB) * originalSize + (CA * aPosition + CB) + Vector2(D, D) * aPosition
+
+      // XA = transformSize * (1.0 - transformOffsetSizeMode.zw)
+      // XB = transformSize * (1.0 - transformOffsetSizeMode.zw) * transformAnchorPoint
+      //    + transformOffset * (1.0 - transformOffsetSizeMode.xy)
+      //    + transformOrigin
+      // CA = transformSize * transformOffsetSizeMode.zw + extraSize
+      // CB = (transformSize * transformOffsetSizeMode.zw + extraSize) * transformAnchorPoint
+      //    + transformOffset * transformOffsetSizeMode.xy
+      // D = max((1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth, 2.0 * blurRadius)
+
+      mVisualPropertiesCoefficient.coefXA = transformSize * Vector2(1.0f - transformOffsetSizeMode.z, 1.0f - transformOffsetSizeMode.w);
+      mVisualPropertiesCoefficient.coefXB = mVisualPropertiesCoefficient.coefXA * transformAnchorPoint + transformOffset * Vector2(1.0f - transformOffsetSizeMode.x, 1.0f - transformOffsetSizeMode.y) + transformOrigin;
+      mVisualPropertiesCoefficient.coefCA = transformSize * Vector2(transformOffsetSizeMode.z, transformOffsetSizeMode.w) + extraSize;
+      mVisualPropertiesCoefficient.coefCB = mVisualPropertiesCoefficient.coefCA * transformAnchorPoint + transformOffset * Vector2(transformOffsetSizeMode.x, transformOffsetSizeMode.y);
+    }
+    if(mVisualProperties->mExtendedProperties)
+    {
+      const auto decoratedVisualProperties = static_cast<DecoratedVisualRenderer::AnimatableDecoratedVisualProperties*>(mVisualProperties->mExtendedProperties);
+
+      uint64_t decoratedHash = 0xc70f6907UL;
+
+      decoratedHash = decoratedVisualProperties->mBorderlineWidth.Hash(updateBufferIndex, decoratedHash);
+      decoratedHash = decoratedVisualProperties->mBorderlineOffset.Hash(updateBufferIndex, decoratedHash);
+      decoratedHash = decoratedVisualProperties->mBlurRadius.Hash(updateBufferIndex, decoratedHash);
+
+      if(mVisualPropertiesCoefficient.decoratedHash != decoratedHash)
+      {
+        mVisualPropertiesCoefficient.decoratedHash = decoratedHash;
+
+        // DecoratedVisualProperty
+        const float borderlineWidth  = decoratedVisualProperties->mBorderlineWidth.Get(updateBufferIndex);
+        const float borderlineOffset = decoratedVisualProperties->mBorderlineOffset.Get(updateBufferIndex);
+        const float blurRadius       = decoratedVisualProperties->mBlurRadius.Get(updateBufferIndex);
+
+        DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "borderline width  %5.3f\n", borderlineWidth);
+        DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "borderline offset %5.3f\n", borderlineOffset);
+        DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "blur radius       %5.3f\n", blurRadius);
+
+        // D coefficients be used only decoratedVisual.
+        // It can be calculated parallely with transform.
+
+        mVisualPropertiesCoefficient.coefD = std::max((1.0f + Dali::Clamp(borderlineOffset, -1.0f, 1.0f)) * borderlineWidth, 2.0f * blurRadius);
+      }
+    }
+
+    // Calculate vertex position by coefficient
+    // It will reduce the number of operations
+
+    // const Vector2 minVertexPosition = (XA * -0.5 + XB) * originalSize + (CA * -0.5 + CB) + Vector2(D, D) * -0.5;
+    // const Vector2 maxVertexPosition = (XA * +0.5 + XB) * originalSize + (CA * +0.5 + CB) + Vector2(D, D) * +0.5;
+
+    // When we set
+    // basicVertexPosition = XB * originalSize + CB
+    // scaleVertexPosition = XA * originalSize + CA + D
+
+    // --> minVertexPosition = basicVertexPosition + scaleVertexPosition * -0.5
+    //     maxVertexPosition = basicVertexPosition + scaleVertexPosition * +0.5
+
+    // Then, resultSize = 2.0f * max(-minVertexPosition, maxVertexPosition);
+    //                  = 2.0f * max(scaleVertexPosition * 0.5 - basicVertexPosition, scaleVertexPosition * 0.5 + basicVertexPosition)
+    //                  = scaleVertexPosition + 2.0f * abs(basicVertexPosition)
+    // Cause transform matrix will think center of vertex is (0, 0)
+
+    const Vector2 basicVertexPosition = mVisualPropertiesCoefficient.coefXB * originalSize.GetVectorXY() + mVisualPropertiesCoefficient.coefCB;
+    const Vector2 scaleVertexPosition = mVisualPropertiesCoefficient.coefXA * originalSize.GetVectorXY() + mVisualPropertiesCoefficient.coefCA;
+
+    // VisualTransform don't set z value. Just copy from original z size
+    const Vector3 resultSize = Vector3(scaleVertexPosition.x + 2.0f * abs(basicVertexPosition.x) + mVisualPropertiesCoefficient.coefD,
+                                       scaleVertexPosition.y + 2.0f * abs(basicVertexPosition.y) + mVisualPropertiesCoefficient.coefD,
+                                       originalSize.z);
+
+    DALI_LOG_INFO(gSceneGraphRendererLogFilter, Debug::Verbose, "%f %f --> %f %f\n", originalSize.x, originalSize.y, resultSize.x, resultSize.y);
+
+    return resultSize;
+  }
+  return originalSize;
+}
+
 } // namespace SceneGraph
 } // namespace Internal
 } // namespace Dali
index 05ea4c6..1e672a0 100644 (file)
@@ -400,10 +400,23 @@ public:
    * Merge shader uniform map into renderer uniform map if any of the
    * maps have changed.  Only update uniform map if added to render
    * instructions.
-   *
-   * @return true if map has been updated, false otherwise
    */
-  bool UpdateUniformMap();
+  void UpdateUniformMap();
+
+  /**
+   * @brief CHeck if the uniformMap regenerated
+   * @return True if the uniformMap changed after latest checkup.
+   * @note The uniform map updated flag is reset after calling this.
+   */
+  [[nodiscard]] inline bool UniformMapUpdated() noexcept
+  {
+    if(mUniformMapUpdated)
+    {
+      mUniformMapUpdated = false;
+      return true;
+    }
+    return false;
+  }
 
   /**
    * Set the given external draw commands on this renderer.
@@ -445,6 +458,16 @@ public: // For VisualProperties
     return mVisualProperties.Get();
   }
 
+  /**
+   * @brief Recalculate size after visual properties applied.
+   *
+   * @param[in] updateBufferIndex The current update buffer index.
+   * @param[in] originalSize The original size before apply the visual properties.
+   *
+   * @return The recalculated size after visual properties applied.
+   */
+  Vector3 CalculateVisualTransformedUpdateSize(BufferIndex updateBufferIndex, const Vector3& originalSize);
+
 private:
   /**
    * Protected constructor; See also Renderer::New()
@@ -488,10 +511,30 @@ private:
   Decay                          mUpdateDecay : 2;       ///< Update decay (aging)
 
   bool                                          mRegenerateUniformMap : 1;     ///< true if the map should be regenerated
+  bool                                          mUniformMapUpdated : 1;        ///< true if the map regenerated recently.
   bool                                          mPremultipledAlphaEnabled : 1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
   std::vector<Dali::DevelRenderer::DrawCommand> mDrawCommands;
   Dali::RenderCallback*                         mRenderCallback{nullptr};
 
+  /**
+   * @brief Cached coefficient value when we calculate visual transformed update size.
+   * It can reduce complexity of calculate the vertex position.
+   *
+   * Vector2 vertexPosition = (XA * aPosition + XB) * originalSize + (CA * aPosition + CB) + Vector2(D, D) * aPosition
+   */
+  struct VisualTransformedUpdateSizeCoefficientCache
+  {
+    Vector2 coefXA{Vector2::ZERO};
+    Vector2 coefXB{Vector2::ZERO};
+    Vector2 coefCA{Vector2::ZERO};
+    Vector2 coefCB{Vector2::ZERO};
+    float   coefD{0.0f};
+
+    uint64_t hash{0u};
+    uint64_t decoratedHash{0u};
+  };
+  VisualTransformedUpdateSizeCoefficientCache mVisualPropertiesCoefficient; ///< Coefficient value to calculate visual transformed update size by VisualProperties more faster.
+
 public:
   AnimatableProperty<float> mOpacity;    ///< The opacity value
   int32_t                   mDepthIndex; ///< Used only in PrepareRenderInstructions
index 80c6364..5bdccc1 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_VECTOR_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/public-api/common/type-traits.h>
 #include <dali/public-api/math/math-utils.h>
 
+/**
+ * @brief For DALi internal use, asserts are enabled in debug builds.
+ *
+ * For Application use, asserts can be enabled manually.
+ * @SINCE_2_1.23
+ */
+#if defined(DEBUG_ENABLED)
+#define ENABLE_VECTOR_ASSERTS
+#endif
+
+#if defined(ENABLE_VECTOR_ASSERTS)
 #define DALI_ASSERT_VECTOR(cond) DALI_ASSERT_ALWAYS(cond)
+#else
+#define DALI_ASSERT_VECTOR(cond)
+#endif
 
 namespace Dali
 {
index ebbefcf..af24b0d 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const uint32_t    CORE_MAJOR_VERSION = 2;
 const uint32_t    CORE_MINOR_VERSION = 1;
-const uint32_t    CORE_MICRO_VERSION = 21;
+const uint32_t    CORE_MICRO_VERSION = 23;
 const char* const CORE_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 03c1f1f..909bc72 100644 (file)
 #include <dali/public-api/render-tasks/render-task-list.h>
 #include <dali/public-api/render-tasks/render-task.h>
 
+#include <dali/public-api/rendering/decorated-visual-renderer.h>
 #include <dali/public-api/rendering/frame-buffer.h>
 #include <dali/public-api/rendering/geometry.h>
 #include <dali/public-api/rendering/renderer.h>
index a3b27bf..97af7b0 100644 (file)
@@ -65,6 +65,7 @@ SET( public_api_src_files
   ${public_api_src_dir}/object/ref-object.cpp
   ${public_api_src_dir}/render-tasks/render-task.cpp
   ${public_api_src_dir}/render-tasks/render-task-list.cpp
+  ${public_api_src_dir}/rendering/decorated-visual-renderer.cpp
   ${public_api_src_dir}/rendering/frame-buffer.cpp
   ${public_api_src_dir}/rendering/geometry.cpp
   ${public_api_src_dir}/rendering/vertex-buffer.cpp
@@ -217,6 +218,7 @@ SET( public_api_core_render_tasks_header_files
 
 
 SET( public_api_core_rendering_header_files
+  ${public_api_src_dir}/rendering/decorated-visual-renderer.h
   ${public_api_src_dir}/rendering/frame-buffer.h
   ${public_api_src_dir}/rendering/geometry.h
   ${public_api_src_dir}/rendering/vertex-buffer.h
diff --git a/dali/public-api/rendering/decorated-visual-renderer.cpp b/dali/public-api/rendering/decorated-visual-renderer.cpp
new file mode 100644 (file)
index 0000000..debf485
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/rendering/decorated-visual-renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/event/rendering/decorated-visual-renderer-impl.h>
+
+namespace Dali
+{
+DecoratedVisualRenderer DecoratedVisualRenderer::New(Geometry& geometry, Shader& shader)
+{
+  Internal::DecoratedVisualRendererPtr renderer = Internal::DecoratedVisualRenderer::New();
+  renderer->SetGeometry(GetImplementation(geometry));
+  renderer->SetShader(GetImplementation(shader));
+  return DecoratedVisualRenderer(renderer.Get());
+}
+
+DecoratedVisualRenderer::DecoratedVisualRenderer() = default;
+
+DecoratedVisualRenderer::~DecoratedVisualRenderer() = default;
+
+DecoratedVisualRenderer::DecoratedVisualRenderer(const DecoratedVisualRenderer& handle) = default;
+
+DecoratedVisualRenderer DecoratedVisualRenderer::DownCast(BaseHandle handle)
+{
+  return DecoratedVisualRenderer(dynamic_cast<Dali::Internal::DecoratedVisualRenderer*>(handle.GetObjectPtr()));
+}
+
+DecoratedVisualRenderer& DecoratedVisualRenderer::operator=(const DecoratedVisualRenderer& handle) = default;
+
+DecoratedVisualRenderer::DecoratedVisualRenderer(DecoratedVisualRenderer&& rhs) = default;
+
+DecoratedVisualRenderer& DecoratedVisualRenderer::operator=(DecoratedVisualRenderer&& rhs) = default;
+
+void DecoratedVisualRenderer::RegisterCornerRadiusUniform()
+{
+  GetImplementation(*this).RegisterCornerRadiusUniform();
+}
+
+void DecoratedVisualRenderer::RegisterBorderlineUniform()
+{
+  GetImplementation(*this).RegisterBorderlineUniform();
+}
+
+void DecoratedVisualRenderer::RegisterBlurRadiusUniform()
+{
+  GetImplementation(*this).RegisterBlurRadiusUniform();
+}
+
+DecoratedVisualRenderer::DecoratedVisualRenderer(Internal::DecoratedVisualRenderer* pointer)
+: Dali::VisualRenderer(pointer)
+{
+}
+
+} //namespace Dali
diff --git a/dali/public-api/rendering/decorated-visual-renderer.h b/dali/public-api/rendering/decorated-visual-renderer.h
new file mode 100644 (file)
index 0000000..80563a2
--- /dev/null
@@ -0,0 +1,232 @@
+#ifndef DALI_DECOREATED_VISUAL_RENDERER_H
+#define DALI_DECOREATED_VISUAL_RENDERER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/rendering/visual-renderer.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_core_rendering_effects
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+class DecoratedVisualRenderer;
+}
+
+/**
+ * @brief DecoratedVisualRenderer is a handle to a Renderer with extra properties for Toolkit::Visuals with some decoration
+ *
+ * @SINCE_2_1.21
+ */
+class DALI_CORE_API DecoratedVisualRenderer : public VisualRenderer
+{
+public:
+  /**
+   * @brief Enumeration for instances of properties belonging to the DecoratedVisualRenderer class.
+   * @SINCE_2_1.21
+   */
+  struct Property
+  {
+    static constexpr Dali::Property::Index DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX = VisualRenderer::Property::DEFAULT_VISUAL_RENDERER_PROPERTY_START_INDEX + DEFAULT_PROPERTY_MAX_COUNT_PER_DERIVATION;
+
+    /**
+     * @brief Enumeration for instances of properties belonging to the DecoratedVisualRenderer class.
+     * @SINCE_2_1.21
+     */
+    enum
+    {
+      /**
+       * @brief The radius for the rounded corners of the visual.
+       * @details Name "cornerRadius", type Property::Vector4, animatable.
+       *
+       * @see Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS
+       * @SINCE_2_1.21
+       * @note The default value is (0, 0, 0, 0).
+       */
+      CORNER_RADIUS = DEFAULT_DECORATED_VISUAL_RENDERER_PROPERTY_START_INDEX,
+
+      /**
+       * @brief Whether the CORNER_RADIUS values are relative (percentage [0.0f to 0.5f] of the control) or absolute (in world units).
+       * @details Name "cornerRadiusPolicy", type Property::FLOAT
+       *
+       * @code
+       * decoratedVisualRenderer.SetProperty( DecoratedVisualRenderer::Property::CORNER_RADIUS_POLICY, Policy::ABSOLUTE );
+       * @endcode
+       *
+       * @see Policy::Type
+       * @see Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY
+       * @SINCE_2_1.21
+       * @note The default value is Policy::RELATIVE.
+       */
+      CORNER_RADIUS_POLICY,
+
+      /**
+       * @brief The width for the borderline of the visual.
+       * @details Name "borderlineWidth", type Property::FLOAT, animatable.
+       *
+       * @see Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH
+       * @SINCE_2_1.21
+       * @note The default value is 0.0.
+       */
+      BORDERLINE_WIDTH,
+
+      /**
+       * @brief The color for the borderline of the visual.
+       * @details Name "borderlineColor", type Property::Vector4, animatable.
+       *
+       * @see Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR
+       * @SINCE_2_1.21
+       * @note The default value is Color::BLACK.
+       */
+      BORDERLINE_COLOR,
+
+      /**
+       * @brief The offset from the visual borderline (recommend [-1.0f to 1.0f]).
+       * @details Name "borderlineOffset", type Property::FLOAT, animatable.
+       *
+       * @see Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET
+       * @SINCE_2_1.21
+       * @note The default value is 0.0f.
+       */
+      BORDERLINE_OFFSET,
+
+      /**
+       * @brief The blur radius of the visual.
+       * @details Name "blurRadius", type Property::FLOAT, animatable.
+       *          If the value is 0, the edge is sharp. Otherwise, the larger the value, the more the edge is blurred.
+       *
+       * @see Dali::Toolkit::DevelColorVisual::Property::BLUR_RADIUS
+       * @SINCE_2_1.21
+       * @note The default value is 0.0f.
+       */
+      BLUR_RADIUS,
+    };
+  };
+
+  /**
+   * @brief Creates a new DecoratedVisualRenderer object.
+   *
+   * @SINCE_2_1.21
+   * @param[in] geometry Geometry to be used by this renderer
+   * @param[in] shader Shader to be used by this renderer
+   * @return A handle to the Renderer
+   */
+  static DecoratedVisualRenderer New(Geometry& geometry, Shader& shader);
+
+  /**
+   * @brief Default constructor, creates an empty handle
+   *
+   * @SINCE_2_1.21
+   */
+  DecoratedVisualRenderer();
+
+  /**
+   * @brief Destructor.
+   *
+   * @SINCE_2_1.21
+   */
+  ~DecoratedVisualRenderer();
+
+  /**
+   * @brief Copy constructor, creates a new handle to the same object.
+   *
+   * @SINCE_2_1.21
+   * @param[in] handle Handle to an object
+   */
+  DecoratedVisualRenderer(const DecoratedVisualRenderer& handle);
+
+  /**
+   * @brief Downcasts to a decorated visual renderer handle.
+   * If not, a renderer the returned decorated visual renderer handle is left uninitialized.
+   *
+   * @SINCE_2_1.21
+   * @param[in] handle Handle to an object
+   * @return Renderer handle or an uninitialized handle
+   */
+  static DecoratedVisualRenderer DownCast(BaseHandle handle);
+
+  /**
+   * @brief Assignment operator, changes this handle to point at the same object.
+   *
+   * @SINCE_2_1.21
+   * @param[in] handle Handle to an object
+   * @return Reference to the assigned object
+   */
+  DecoratedVisualRenderer& operator=(const DecoratedVisualRenderer& handle);
+
+  /**
+   * @brief Register relate with corner radius uniforms so we can use it as uniform properties.
+   *
+   * @SINCE_2_1.21
+   */
+  void RegisterCornerRadiusUniform();
+
+  /**
+   * @brief Register relate with borderline uniforms so we can use it as uniform properties.
+   *
+   * @SINCE_2_1.21
+   */
+  void RegisterBorderlineUniform();
+
+  /**
+   * @brief Register relate with blur radius uniforms so we can use it as uniform properties.
+   *
+   * @SINCE_2_1.21
+   */
+  void RegisterBlurRadiusUniform();
+
+  /**
+   * @brief Move constructor.
+   *
+   * @SINCE_2_1.21
+   * @param[in] rhs A reference to the moved handle
+   */
+  DecoratedVisualRenderer(DecoratedVisualRenderer&& rhs);
+
+  /**
+   * @brief Move assignment operator.
+   *
+   * @SINCE_2_1.21
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this handle
+   */
+  DecoratedVisualRenderer& operator=(DecoratedVisualRenderer&& rhs);
+
+public:
+  /// @cond internal
+  /**
+   * @brief The constructor.
+   * @note  Not intended for application developers.
+   * @SINCE_2_1.21
+   * @param[in] pointer A pointer to a newly allocated DecoratedVisualRenderer
+   */
+  explicit DALI_INTERNAL DecoratedVisualRenderer(Internal::DecoratedVisualRenderer* pointer);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} //namespace Dali
+
+#endif // DALI_DECOREATED_VISUAL_RENDERER_H
index a8c55ad..5e7b66c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/public-api/signals/base-signal.h>
 
 // EXTERNAL INCLUDES
-#include <algorithm> // remove_if
+#include <unordered_map>
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
 
 namespace
 {
-const int32_t INVALID_CALLBACK_INDEX = -1;
-
+struct CallbackBasePtrHash
+{
+  std::size_t operator()(const Dali::CallbackBase* callback) const noexcept
+  {
+    std::size_t functionHash = reinterpret_cast<std::size_t>(reinterpret_cast<void*>(callback->mFunction));
+    std::size_t objectHash   = reinterpret_cast<std::size_t>(reinterpret_cast<void*>(callback->mImpl.mObjectPointer));
+    return functionHash ^ objectHash;
+  }
+};
+struct CallbackBasePtrEqual
+{
+  bool operator()(const Dali::CallbackBase* lhs, const Dali::CallbackBase* rhs) const noexcept
+  {
+    return (*lhs) == (*rhs);
+  }
+};
 } // unnamed namespace
 
 namespace Dali
 {
+/**
+ * @brief Extra struct for callback base cache.
+ */
+struct BaseSignal::Impl
+{
+  Impl()  = default;
+  ~Impl() = default;
+
+  /**
+   * @brief Get the iterator of connections list by the callback base pointer.
+   * Note that we should compare the 'value' of callback, not pointer.
+   * So, we need to define custom hash & compare functor of callback base pointer.
+   */
+  std::unordered_map<const CallbackBase*, std::list<SignalConnection>::iterator, CallbackBasePtrHash, CallbackBasePtrEqual> mCallbackCache;
+};
+
 BaseSignal::BaseSignal()
-: mEmittingFlag(false)
+: mCacheImpl(new BaseSignal::Impl()),
+  mEmittingFlag(false)
 {
 }
 
@@ -53,10 +84,9 @@ BaseSignal::~BaseSignal()
 
   // The signal is being destroyed. We have to inform any slots
   // that are connected, that the signal is dead.
-  const std::size_t count(mSignalConnections.size());
-  for(std::size_t i = 0; i < count; i++)
+  for(auto iter = mSignalConnections.begin(), iterEnd = mSignalConnections.end(); iter != iterEnd; ++iter)
   {
-    auto& connection = mSignalConnections[i];
+    auto& connection = *iter;
 
     // Note that values are set to NULL in DeleteConnection
     if(connection)
@@ -64,21 +94,23 @@ BaseSignal::~BaseSignal()
       connection.Disconnect(this);
     }
   }
+
+  delete mCacheImpl;
 }
 
 void BaseSignal::OnConnect(CallbackBase* callback)
 {
   DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Connect()");
 
-  int32_t index = FindCallback(callback);
+  auto iter = FindCallback(callback);
 
   // Don't double-connect the same callback
-  if(INVALID_CALLBACK_INDEX == index)
+  if(iter == mSignalConnections.end())
   {
-    // create a new signal connection object, to allow the signal to track the connection.
-    //SignalConnection* connection = new SignalConnection(callback);
+    auto newIter = mSignalConnections.insert(mSignalConnections.end(), SignalConnection(callback));
 
-    mSignalConnections.push_back(SignalConnection(callback));
+    // Store inserted iterator for this callback
+    mCacheImpl->mCallbackCache[callback] = newIter;
   }
   else
   {
@@ -91,11 +123,11 @@ void BaseSignal::OnDisconnect(CallbackBase* callback)
 {
   DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Disconnect()");
 
-  int32_t index = FindCallback(callback);
+  auto iter = FindCallback(callback);
 
-  if(index > INVALID_CALLBACK_INDEX)
+  if(iter != mSignalConnections.end())
   {
-    DeleteConnection(index);
+    DeleteConnection(iter);
   }
 
   // call back is a temporary created to find which slot should be disconnected.
@@ -107,15 +139,15 @@ void BaseSignal::OnConnect(ConnectionTrackerInterface* tracker, CallbackBase* ca
   DALI_ASSERT_ALWAYS(nullptr != tracker && "Invalid ConnectionTrackerInterface pointer passed to Connect()");
   DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Connect()");
 
-  int32_t index = FindCallback(callback);
+  auto iter = FindCallback(callback);
 
   // Don't double-connect the same callback
-  if(INVALID_CALLBACK_INDEX == index)
+  if(iter == mSignalConnections.end())
   {
-    // create a new signal connection object, to allow the signal to track the connection.
-    //SignalConnection* connection = new SignalConnection(tracker, callback);
+    auto newIter = mSignalConnections.insert(mSignalConnections.end(), {tracker, callback});
 
-    mSignalConnections.push_back({tracker, callback});
+    // Store inserted iterator for this callback
+    mCacheImpl->mCallbackCache[callback] = newIter;
 
     // Let the connection tracker know that a connection between a signal and a slot has been made.
     tracker->SignalConnected(this, callback);
@@ -132,15 +164,16 @@ void BaseSignal::OnDisconnect(ConnectionTrackerInterface* tracker, CallbackBase*
   DALI_ASSERT_ALWAYS(nullptr != tracker && "Invalid ConnectionTrackerInterface pointer passed to Disconnect()");
   DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Disconnect()");
 
-  int32_t index = FindCallback(callback);
+  auto iter = FindCallback(callback);
 
-  if(index > INVALID_CALLBACK_INDEX)
+  if(iter != mSignalConnections.end())
   {
     // temporary pointer to disconnected callback
-    CallbackBase* disconnectedCallback = mSignalConnections[index].GetCallback();
+    // Note that (*iter).GetCallback() != callback is possible.
+    CallbackBase* disconnectedCallback = (*iter).GetCallback();
 
     // close the signal side connection first.
-    DeleteConnection(index);
+    DeleteConnection(iter);
 
     // close the slot side connection
     tracker->SignalDisconnected(this, disconnectedCallback);
@@ -153,62 +186,55 @@ void BaseSignal::OnDisconnect(ConnectionTrackerInterface* tracker, CallbackBase*
 // for SlotObserver::SlotDisconnected
 void BaseSignal::SlotDisconnected(CallbackBase* callback)
 {
-  const std::size_t count(mSignalConnections.size());
-  for(std::size_t i = 0; i < count; ++i)
-  {
-    const CallbackBase* connectionCallback = GetCallback(i);
-
-    // Pointer comparison i.e. SignalConnection contains pointer to same callback instance
-    if(connectionCallback &&
-       connectionCallback == callback)
-    {
-      DeleteConnection(i);
+  DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid callback function passed to SlotObserver::SlotDisconnected()");
 
-      // Disconnection complete
-      return;
-    }
+  auto iter = FindCallback(callback);
+  if(DALI_LIKELY(iter != mSignalConnections.end()))
+  {
+    DeleteConnection(iter);
+    return;
   }
 
   DALI_ABORT("Callback lost in SlotDisconnected()");
 }
 
-int32_t BaseSignal::FindCallback(CallbackBase* callback) const noexcept
+std::list<SignalConnection>::iterator BaseSignal::FindCallback(CallbackBase* callback) noexcept
 {
-  int32_t index(INVALID_CALLBACK_INDEX);
+  const auto& convertorIter = mCacheImpl->mCallbackCache.find(callback);
 
-  // A signal can have multiple slots connected to it.
-  // We need to search for the slot which has the same call back function (if it's static)
-  // Or the same object / member function (for non-static)
-  for(auto i = 0u; i < mSignalConnections.size(); ++i)
+  if(convertorIter != mCacheImpl->mCallbackCache.end())
   {
-    const CallbackBase* connectionCallback = GetCallback(i);
+    const auto& iter = convertorIter->second; // std::list<SignalConnection>::iterator
 
-    // Note that values are set to NULL in DeleteConnection
-    if(connectionCallback && (*connectionCallback == *callback))
+    if(*iter) // the value of iterator can be null.
     {
-      index = static_cast<int>(i); // only 2,147,483,647 connections supported, no error check
-      break;
+      if(*(iter->GetCallback()) == *callback)
+      {
+        return iter;
+      }
     }
   }
-
-  return index;
+  return mSignalConnections.end();
 }
 
-void BaseSignal::DeleteConnection(std::size_t connectionIndex)
+void BaseSignal::DeleteConnection(std::list<SignalConnection>::iterator iter)
 {
+  // Erase cache first.
+  mCacheImpl->mCallbackCache.erase(iter->GetCallback());
+
   if(mEmittingFlag)
   {
     // IMPORTANT - do not remove from items from mSignalConnections, reset instead.
     // Signal Emit() methods require that connection count is not reduced while iterating
     // i.e. DeleteConnection can be called from within callbacks, while iterating through mSignalConnections.
-    mSignalConnections[connectionIndex] = {nullptr};
+    (*iter) = {nullptr};
     ++mNullConnections;
   }
   else
   {
     // If application connects and disconnects without the signal never emitting,
     // the mSignalConnections vector keeps growing and growing as CleanupConnections() is done from Emit.
-    mSignalConnections.erase(mSignalConnections.begin() + connectionIndex);
+    mSignalConnections.erase(iter);
   }
 }
 
@@ -217,10 +243,7 @@ void BaseSignal::CleanupConnections()
   if(!mSignalConnections.empty())
   {
     //Remove Signals that are already markeed nullptr.
-    mSignalConnections.erase(std::remove_if(mSignalConnections.begin(),
-                                            mSignalConnections.end(),
-                                            [](auto& elm) { return (elm) ? false : true; }),
-                             mSignalConnections.end());
+    mSignalConnections.remove_if([](auto& elem) { return (elem) ? false : true; });
   }
   mNullConnections = 0;
 }
index b63e1e2..5420952 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_BASE_SIGNAL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 // EXTERNAL INCLUDES
-#include <vector>
+#include <stdint.h> // for uint32_t
 
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/list-wrapper.h>
 #include <dali/public-api/signals/callback.h>
 #include <dali/public-api/signals/connection-tracker-interface.h>
 #include <dali/public-api/signals/signal-slot-connections.h>
@@ -175,14 +175,12 @@ public:
 
     // If more connections are added by callbacks, these are ignore until the next Emit()
     // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
+    auto count = mSignalConnections.size();
+    auto iter  = mSignalConnections.begin();
+    while(count--)
     {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
+      CallbackBase* callback((*iter) ? iter->GetCallback() : nullptr);
+      ++iter;
       if(callback)
       {
         returnVal = CallbackBase::ExecuteReturn<Ret, Args...>(*callback, args...);
@@ -222,14 +220,12 @@ public:
 
     // If more connections are added by callbacks, these are ignore until the next Emit()
     // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.size());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
+    auto count = mSignalConnections.size();
+    auto iter  = mSignalConnections.begin();
+    while(count--)
     {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
+      CallbackBase* callback((*iter) ? iter->GetCallback() : nullptr);
+      ++iter;
       if(callback)
       {
         CallbackBase::Execute<Args...>(*callback, args...);
@@ -288,33 +284,21 @@ private: // SlotObserver interface, to be told when a slot disconnects
 
 private:
   /**
-   * @brief Returns a callback given an index in to the connection array.
-   *
-   * @SINCE_1_0.0
-   * @param[in] connectionIndex The index of the callback
-   * @return The callback, or NULL if the connection has been deleted
-   */
-  CallbackBase* GetCallback(std::size_t connectionIndex) const noexcept
-  {
-    return mSignalConnections[connectionIndex].GetCallback();
-  }
-
-  /**
    * @brief Helper to find whether a callback is connected.
    *
-   * @SINCE_1_0.0
+   * @SINCE_2_1.22
    * @param[in] callback The call back object
    * @return A valid index if the callback is connected
    */
-  int32_t FindCallback(CallbackBase* callback) const noexcept;
+  std::list<SignalConnection>::iterator FindCallback(CallbackBase* callback) noexcept;
 
   /**
    * @brief Deletes a connection object from the list of connections.
    *
-   * @SINCE_1_0.0
-   * @param[in] connectionIndex The index of the callback
+   * @SINCE_2_1.22
+   * @param[in] iter The index of the callback
    */
-  void DeleteConnection(std::size_t connectionIndex);
+  void DeleteConnection(std::list<SignalConnection>::iterator iter);
 
   /**
    * @brief Helper to remove NULL items from mSignalConnections, which is only safe at the end of Emit()
@@ -329,10 +313,14 @@ private:
   BaseSignal& operator=(BaseSignal&&) = delete;      ///< Deleted move assignment operator. @SINCE_1_9.25
 
 private:
-  std::vector<SignalConnection> mSignalConnections;      ///< Array of connections
-  uint32_t                      mNullConnections{0};     ///< Empty Connections in the array.
-  bool                          mEmittingFlag{false};    ///< Used to guard against nested Emit() calls.
-  bool*                         mSignalDeleted{nullptr}; ///< Used to guard against deletion during Emit() calls.
+  struct DALI_INTERNAL Impl;
+  Impl*                mCacheImpl; ///< Private internal extra data.
+
+private:
+  std::list<SignalConnection> mSignalConnections{};    ///< List of connections
+  uint32_t                    mNullConnections{0};     ///< Empty Connections in the array.
+  bool                        mEmittingFlag{false};    ///< Used to guard against nested Emit() calls.
+  bool*                       mSignalDeleted{nullptr}; ///< Used to guard against deletion during Emit() calls.
 };
 
 /**
index 5ff2732..42ed2d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // CLASS HEADER
 #include <dali/public-api/signals/connection-tracker.h>
 
+// EXTERNAL INCLUDES
+#include <unordered_map>
+
+// INTERNAL INCLUDES
 #include <dali/public-api/signals/callback.h>
-#include <dali/public-api/signals/signal-slot-connections.h>
 #include <dali/public-api/signals/signal-slot-observers.h>
 
 namespace Dali
 {
-ConnectionTracker::ConnectionTracker() = default;
+/**
+ * @brief Extra struct for callback base cache.
+ */
+struct ConnectionTracker::Impl
+{
+  Impl()  = default;
+  ~Impl() = default;
+
+  std::unordered_map<CallbackBase*, SlotObserver*> mCallbackCache;
+};
+
+ConnectionTracker::ConnectionTracker()
+: mCacheImpl(new ConnectionTracker::Impl())
+{
+}
 
 ConnectionTracker::~ConnectionTracker()
 {
   DisconnectAll();
+  delete mCacheImpl;
 }
 
 void ConnectionTracker::DisconnectAll()
 {
-  std::size_t size = mConnections.Size();
-
-  for(std::size_t i = 0; i < size; ++i)
+  // Iterate unordered list of CallbackBase / SlotObserver.
+  // Note that we don't need to keep order of ConnectionTracker::SignalConnected
+  for(auto iter = mCacheImpl->mCallbackCache.begin(), iterEnd = mCacheImpl->mCallbackCache.end(); iter != iterEnd; ++iter)
   {
-    auto& connection = mConnections[i];
+    auto& callbackBase = iter->first;
+    auto& slotObserver = iter->second;
 
     // Tell the signal that the slot is disconnected
-    connection.GetSlotObserver()->SlotDisconnected(connection.GetCallback());
+    slotObserver->SlotDisconnected(callbackBase);
   }
 
-  mConnections.Clear();
+  mCacheImpl->mCallbackCache.clear();
+  mCacheImpl->mCallbackCache.rehash(0); ///< Note : unordered_map.clear() didn't deallocate memory.
 }
 
 void ConnectionTracker::SignalConnected(SlotObserver* slotObserver, CallbackBase* callback)
 {
-  mConnections.PushBack(SlotConnection(slotObserver, callback));
+  // We can assume that there is no duplicated callback come here
+  mCacheImpl->mCallbackCache[callback] = slotObserver;
 }
 
-void ConnectionTracker::SignalDisconnected(SlotObserver* signal, CallbackBase* callback)
+void ConnectionTracker::SignalDisconnected(SlotObserver* slotObserver, CallbackBase* callback)
 {
-  std::size_t size = mConnections.Size();
-
-  for(std::size_t i = 0; i < size; ++i)
+  // Remove from CallbackBase / SlotObserver list
+  const bool isRemoved = mCacheImpl->mCallbackCache.erase(callback);
+  if(DALI_LIKELY(isRemoved))
   {
-    auto& connection = mConnections[i];
-
-    // Pointer comparison i.e. SignalConnection contains pointer to same callback instance
-    if(connection.GetCallback() == callback)
-    {
-      // Remove from connection list
-      mConnections.Erase(mConnections.Begin() + i);
-
-      // Disconnection complete
-      return;
-    }
+    // Disconnection complete
+    return;
   }
 
   DALI_ABORT("Callback lost in SignalDisconnected()");
@@ -75,7 +87,7 @@ void ConnectionTracker::SignalDisconnected(SlotObserver* signal, CallbackBase* c
 
 std::size_t ConnectionTracker::GetConnectionCount() const
 {
-  return mConnections.Size();
+  return mCacheImpl->mCallbackCache.size();
 }
 
 } // namespace Dali
index d2f6262..6232d66 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_CONNECTION_TRACKER_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
+// EXTERNAL INCLUDES
+#include <cstddef> // for std::size_t
+
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
-#include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/signals/connection-tracker-interface.h>
-#include <dali/public-api/signals/signal-slot-connections.h>
+#include <dali/public-api/signals/signal-slot-observers.h>
 
 namespace Dali
 {
@@ -33,7 +35,6 @@ namespace Dali
 
 class CallbackBase;
 class SlotObserver;
-class SlotConnection;
 
 /**
  * @brief Connection tracker concrete implementation.
@@ -84,7 +85,8 @@ private:
   ConnectionTracker& operator=(ConnectionTracker&&) = delete;      ///< Deleted move assignment operator. @SINCE_1_9.25
 
 private:
-  Dali::Vector<SlotConnection> mConnections; ///< Vector of connection
+  struct DALI_INTERNAL Impl;
+  Impl*                mCacheImpl; ///< Private internal extra data.
 };
 
 /**
index c4fd2ed..2c893c7 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_SIGNAL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/signals/base-signal.h>
 #include <dali/public-api/signals/callback.h>
 #include <dali/public-api/signals/signal-slot-connections.h>
index 676a72c..3ee1d0a 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2
 Summary:    DALi 3D Engine
-Version:    2.1.21
+Version:    2.1.23
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT