Apply Visual's transform + borderline properties for partial update 82/274182/21
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 22 Apr 2022 10:02:47 +0000 (19:02 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 12 May 2022 12:16:52 +0000 (21:16 +0900)
Previously, PartialUpdate cannot know the vertex positions
after transform the visual.
But now, we can use VisualRender's animatable properties.

This patch re-calculate the partial update size
so we can consider Visual Transform.

And more, We make DecoratedVisualRenderer so we can use
CornerRadius + etc as default property
and also can re-calculate update size consider with BorderlineWidth or BlurRadius

Change-Id: I99962f7cda3fb51defc439cf5f1517278aa0daa4
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
14 files changed:
automated-tests/src/dali/CMakeLists.txt
automated-tests/src/dali/utc-Dali-DecoratedVisualRenderer.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-VisualRenderer.cpp
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.h
dali/internal/file.list
dali/internal/update/manager/render-instruction-processor.cpp
dali/internal/update/rendering/scene-graph-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer.h
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]

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
 )
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 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
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 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 d021083..0592ad9 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;
@@ -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 a0f4b4e..931244a 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;
 
@@ -693,6 +700,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..171042c 100644 (file)
@@ -445,6 +445,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()
@@ -492,6 +502,25 @@ private:
   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 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