Merge "Add TOUCH_FOCUSABLE property" into devel/master
authorjoogab yun <joogab.yun@samsung.com>
Tue, 15 Jun 2021 05:35:22 +0000 (05:35 +0000)
committerGerrit Code Review <gerrit@review>
Tue, 15 Jun 2021 05:35:22 +0000 (05:35 +0000)
85 files changed:
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-Transition.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
dali-toolkit/devel-api/controls/accessible-impl.cpp
dali-toolkit/devel-api/controls/accessible-impl.h
dali-toolkit/devel-api/controls/control-devel.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/layouting/flex-node.h
dali-toolkit/devel-api/visuals/visual-properties-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.h
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h
dali-toolkit/internal/controls/web-view/web-view-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/graphics/shaders/color-visual-shader.vert
dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-linear-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-linear-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-radial-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-radial-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-atlas-clamp-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-atlas-various-wrap-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-no-atlas-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/image-visual-shader.vert
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/transition/transition-base-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition/transition-base-impl.h [new file with mode: 0644]
dali-toolkit/internal/transition/transition-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition/transition-impl.h [new file with mode: 0644]
dali-toolkit/internal/transition/transition-lifecycle-controller.cpp [new file with mode: 0644]
dali-toolkit/internal/transition/transition-lifecycle-controller.h [new file with mode: 0644]
dali-toolkit/internal/transition/transition-set-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition/transition-set-impl.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/gradient/gradient-visual.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/visual-base-data-impl.cpp
dali-toolkit/internal/visuals/visual-base-data-impl.h
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.h
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h
dali-toolkit/public-api/controls/control-impl.h
dali-toolkit/public-api/controls/flex-container/flex-container.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/file.list
dali-toolkit/public-api/transition/transition-base.cpp [new file with mode: 0644]
dali-toolkit/public-api/transition/transition-base.h [new file with mode: 0644]
dali-toolkit/public-api/transition/transition-set.cpp [new file with mode: 0644]
dali-toolkit/public-api/transition/transition-set.h [new file with mode: 0644]
dali-toolkit/public-api/transition/transition.cpp [new file with mode: 0644]
dali-toolkit/public-api/transition/transition.h [new file with mode: 0644]
docs/content/programming-guide/flex-container.md
packaging/dali-toolkit.spec

index fdd8f10..808cc7a 100644 (file)
@@ -937,3 +937,117 @@ int UtcDaliAccessibilitySignals(void)
 
   END_TEST;
 }
+
+static void Wait(ToolkitTestApplication& application)
+{
+  application.SendNotification();
+  application.Render(16);
+}
+
+int UtcDaliAccessibilityScrollToChildScrollView(void)
+{
+  ToolkitTestApplication application;
+  Dali::Accessibility::TestEnableSC( true );
+
+  ScrollView scrollView = ScrollView::New();
+  application.GetScene().Add( scrollView );
+
+  PushButton actorA = PushButton::New();
+  const Dali::Vector3 positionA = Vector3(100.0f, 400.0f, 0.0f);
+  actorA.SetProperty( Dali::Actor::Property::POSITION, positionA );
+  scrollView.Add(actorA);
+
+  PushButton actorB = PushButton::New();
+  const Dali::Vector3 positionB = Vector3(500.0f, 200.0f, 0.0f);
+  actorB.SetProperty( Dali::Actor::Property::POSITION, positionB );
+  scrollView.Add(actorB);
+
+  Wait(application);
+
+  auto* accessibleParent = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(scrollView));
+  DALI_TEST_CHECK(accessibleParent);
+  auto* accessibleA = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(actorA));
+  DALI_TEST_CHECK(accessibleA);
+  auto* accessibleB = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(actorB));
+  DALI_TEST_CHECK(accessibleB);
+
+  accessibleA->GrabHighlight(); // == scrollView.ScrollTo(actorA)
+  Wait(application);
+  accessibleB->GrabHighlight(); // == scrollView.ScrollTo(actorB)
+  Wait(application);
+
+  Dali::Accessibility::TestEnableSC( false );
+  END_TEST;
+}
+
+namespace {
+  class TestItemFactory : public ItemFactory
+  {
+  public:
+    TestItemFactory()
+    {
+    }
+
+    unsigned int GetNumberOfItems() override
+    {
+      return 2;
+    }
+
+    Dali::Actor NewItem(unsigned int itemId) override
+    {
+      return TextLabel::New(std::to_string(itemId));
+    }
+  };
+}
+
+int UtcDaliAccessibilityScrollToChildItemView(void)
+{
+  ToolkitTestApplication application;
+  Dali::Accessibility::TestEnableSC( true );
+
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+  Dali::Vector3 vec(480.0f, 800.0f, 0.0f);
+  ItemLayoutPtr layout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+
+  view.AddLayout(*layout);
+  view.SetProperty( Actor::Property::SIZE, vec );
+
+  application.GetScene().Add(view);
+  layout->SetOrientation(ControlOrientation::Down);
+  view.ActivateLayout(0, vec, 0.0f);
+
+  Wait(application);
+
+  auto* accessibleParent = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(view));
+  DALI_TEST_CHECK(accessibleParent);
+  auto* accessibleA = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(view.GetItem(0)));
+  DALI_TEST_CHECK(accessibleA);
+  auto* accessibleB = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(view.GetItem(1)));
+  DALI_TEST_CHECK(accessibleB);
+
+  accessibleA->GrabHighlight(); // == view.ScrollToItem(view.GetItemId(actorA))
+  Wait(application);
+  accessibleB->GrabHighlight(); // == view.ScrollToItem(view.GetItemId(actorB))
+  Wait(application);
+
+  Dali::Accessibility::TestEnableSC( false );
+  END_TEST;
+}
+
+int UtcDaliAccessibilityScrollToChildNonScrollable(void)
+{
+  ToolkitTestApplication application;
+  Dali::Accessibility::TestEnableSC( true );
+
+  TextLabel label = TextLabel::New("123");
+
+  auto* accessible = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(label));
+  DALI_TEST_CHECK(accessible);
+
+  DALI_TEST_EQUALS(accessible->IsScrollable(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(accessible->ScrollToChild({}), false, TEST_LOCATION);
+
+  Dali::Accessibility::TestEnableSC( false );
+  END_TEST;
+}
\ No newline at end of file
index 2983fd7..2b73142 100755 (executable)
@@ -44,6 +44,7 @@ SET(TC_SOURCES
   utc-Dali-TextureManager.cpp
   utc-Dali-ToolBar.cpp
   utc-Dali-Tooltip.cpp
+  utc-Dali-Transition.cpp
   utc-Dali-TransitionData.cpp
   utc-Dali-Button.cpp
   utc-Dali-CameraView.cpp
index 6d74b7c..56d67f4 100644 (file)
@@ -77,7 +77,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
     .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
     .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
     .Add( DevelVisual::Property::CORNER_RADIUS, 22.2f )
-    .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE ));
+    .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE )
+    .Add( DevelVisual::Property::BORDERLINE_WIDTH, 33.3f )
+    .Add( DevelVisual::Property::BORDERLINE_COLOR, Color::RED )
+    .Add( DevelVisual::Property::BORDERLINE_OFFSET, 0.3f ));
 
   Property::Map resultMap;
   animatedImageVisual.CreatePropertyMap( resultMap );
@@ -98,6 +101,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::ABSOLUTE );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 33.3f, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Color::RED, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.3f, TEST_LOCATION );
+
   // request AnimatedImageVisual with an URL
   Visual::Base animatedImageVisual2 = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
   resultMap.Clear();
@@ -137,7 +152,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
     .Add( "wrapModeU", WrapMode::REPEAT )
     .Add( "wrapModeV", WrapMode::DEFAULT )
     .Add( "cornerRadius", Vector4(50.0f, 25.0f, 12.5f, 33.0f) )
-    .Add( "cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE ));
+    .Add( "cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE )
+    .Add( "borderlineWidth", 20.0f )
+    .Add( "borderlineColor", Vector4() )
+    .Add( "borderlineOffset", -1.0f));
 
   Property::Map resultMap;
   animatedImageVisual.CreatePropertyMap( resultMap );
@@ -180,6 +198,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::RELATIVE );
 
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 20.0f, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4::ZERO, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), -1.0f, TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -248,6 +278,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::ABSOLUTE );
 
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Color::BLACK, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -264,7 +306,8 @@ int UtcDaliAnimatedImageVisualGetPropertyMap04(void)
     .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
     .Add( ImageVisual::Property::BATCH_SIZE, 1 )
     .Add( ImageVisual::Property::CACHE_SIZE, 1 )
-    .Add( ImageVisual::Property::SYNCHRONOUS_LOADING, false ));
+    .Add( ImageVisual::Property::SYNCHRONOUS_LOADING, false )
+    .Add( DevelVisual::Property::BORDERLINE_WIDTH, 0.4f ));
 
   Property::Map resultMap;
   animatedImageVisual.CreatePropertyMap( resultMap );
@@ -290,6 +333,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap04(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<int>(), 4, TEST_LOCATION );
 
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.4f, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4(0.0f, 0.0f, 0.0f, 1.0f), TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
   END_TEST;
 }
 
index 83c6a09..6159e71 100644 (file)
@@ -145,7 +145,8 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual03(void)
              .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
              .Add( DevelImageVisual::Property::LOOP_COUNT, 3  )
              .Add( DevelImageVisual::Property::PLAY_RANGE, playRange  )
-             .Add( DevelVisual::Property::CORNER_RADIUS, 50.0f );
+             .Add( DevelVisual::Property::CORNER_RADIUS, 50.0f )
+             .Add( DevelVisual::Property::BORDERLINE_WIDTH, 20.0f );
 
   Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
   DALI_TEST_CHECK( visual );
@@ -177,6 +178,9 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
 
   int startFrame = 1, endFrame = 3;
   float cornerRadius = 22.0f;
+  float borderlineWidth = 2.0f;
+  Vector4 borderlineColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
+  float borderlineOffset = 0.1f;
   Property::Array playRange;
   playRange.PushBack( startFrame );
   playRange.PushBack( endFrame );
@@ -189,7 +193,10 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
              .Add( "stopBehavior", DevelImageVisual::StopBehavior::FIRST_FRAME )
              .Add( "loopingMode", DevelImageVisual::LoopingMode::AUTO_REVERSE )
              .Add( "redrawInScalingDown", false )
-             .Add( "cornerRadius", cornerRadius );
+             .Add( "cornerRadius", cornerRadius )
+             .Add( "borderlineWidth", borderlineWidth )
+             .Add( "borderlineColor", borderlineColor )
+             .Add( "borderlineOffset", borderlineOffset );
 
   Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
   DALI_TEST_CHECK( visual );
@@ -253,6 +260,18 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get< int >() == Visual::Transform::Policy::ABSOLUTE );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineWidth, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< Vector4 >(), borderlineColor, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineOffset, TEST_LOCATION );
+
   actor.Unparent( );
   DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
 
@@ -266,6 +285,9 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
 
   int startFrame = 1, endFrame = 3;
   Vector4 cornerRadius(50.0f, 22.0f, 0.0f, 3.0f);
+  float borderlineWidth = 2.3f;
+  Vector4 borderlineColor = Vector4(0.3f, 0.3f, 1.0f, 1.0f);
+  float borderlineOffset = 0.3f;
   Property::Array playRange;
   playRange.PushBack( startFrame );
   playRange.PushBack( endFrame );
@@ -276,7 +298,10 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
              .Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
              .Add( DevelImageVisual::Property::PLAY_RANGE, playRange )
              .Add( DevelVisual::Property::CORNER_RADIUS, cornerRadius )
-             .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::RELATIVE);
+             .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::RELATIVE)
+             .Add( DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth )
+             .Add( DevelVisual::Property::BORDERLINE_COLOR, borderlineColor )
+             .Add( DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset );
 
   // request AnimatedVectorImageVisual with a property map
   VisualFactory factory = VisualFactory::Get();
@@ -344,6 +369,18 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get< int >() == Visual::Transform::Policy::RELATIVE );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineWidth, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< Vector4 >(), borderlineColor, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineOffset, TEST_LOCATION );
+
   // request AnimatedVectorImageVisual with an URL
   Visual::Base visual2 = factory.CreateVisual( TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions() );
 
@@ -1774,4 +1811,4 @@ int UtcDaliAnimatedVectorImageVisualPlaybackRiveFile(void)
   }
 
   END_TEST;
-}
\ No newline at end of file
+}
index fa48c76..675e2c7 100644 (file)
@@ -3519,6 +3519,49 @@ int utcDaliTextEditorGetHeightForWidthDoesNotChangeLineCountLineWrapCharCase(voi
   END_TEST;
 }
 
+int utcDaliTextEditorGetHeightForWidthChangeLineCountWhenTextChanged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" utcDaliTextEditorGetHeightForWidthChangeLineCountWhenTextChanged ");
+
+  int lineCountBefore =0 ;
+  int lineCountAfter =0 ;
+
+  // Create a text editor
+  TextEditor textEditor = TextEditor::New();
+  //Set very large font-size using point-size
+  textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 10) ;
+  //Specify font-family
+  textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+  //Specify size
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 100.f ) );
+  //Set text longer than width of textEditor
+  textEditor.SetProperty( TextEditor::Property::TEXT, "Short text");
+  //Set line wrap mode Character
+  textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, "CHARACTER");
+
+  application.GetScene().Add( textEditor );
+
+  application.SendNotification();
+  application.Render();
+
+
+  lineCountBefore =  textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+  textEditor.SetProperty( TextEditor::Property::TEXT, "This is very loooooooooooooooooooooooooooooooooooong text for test");
+  lineCountAfter =  textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+  // When the text changed, the Line-count should be updated according to new text.
+  // Because the GetHeightForWidth is called in Controller::GetLineCount(float width)
+  DALI_TEST_EQUALS( lineCountBefore ,1, TEST_LOCATION );
+  DALI_TEST_GREATER( lineCountAfter,1, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+
 int utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountScrollingCase(void)
 {
   ToolkitTestApplication application;
index ac7403b..9a187d6 100644 (file)
@@ -1885,3 +1885,47 @@ int UtcDaliTextLabelHyphenWrapMode(void)
 
   END_TEST;
 }
+
+
+int utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged ");
+
+  int lineCountBefore =0 ;
+  int lineCountAfter =0 ;
+
+  // Create a text editor
+  TextLabel textLabel = TextLabel::New();
+  //Set very large font-size using point-size
+  textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 10) ;
+  //Specify font-family
+  textLabel.SetProperty( TextLabel::Property::FONT_FAMILY, "DejaVu Sans");
+  //Specify size
+  textLabel.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 100.f ) );
+  //Set text longer than width of textLabel
+  textLabel.SetProperty( TextLabel::Property::TEXT, "Short text");
+  //Set line wrap mode Character
+  textLabel.SetProperty(TextLabel::Property::LINE_WRAP_MODE, "CHARACTER");
+  textLabel.SetProperty(TextLabel::Property::MULTI_LINE, true);
+
+  application.GetScene().Add( textLabel );
+
+  application.SendNotification();
+  application.Render();
+
+
+  lineCountBefore =  textLabel.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+
+  textLabel.SetProperty( TextLabel::Property::TEXT, "This is very loooooooooooooooooooooooooooooooooooong text for test");
+  lineCountAfter =  textLabel.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+
+  // When the text changed, the Line-count should be updated according to new text.
+  // Because the GetHeightForWidth is called in Controller::GetLineCount(float width)
+  DALI_TEST_EQUALS( lineCountBefore ,1, TEST_LOCATION );
+  DALI_TEST_GREATER( lineCountAfter,1, TEST_LOCATION );
+
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Transition.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Transition.cpp
new file mode 100755 (executable)
index 0000000..b694a69
--- /dev/null
@@ -0,0 +1,929 @@
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/public-api/transition/transition-set.h>
+#include <dali-toolkit/public-api/transition/transition-base.h>
+#include <dali-toolkit/public-api/transition/transition.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+namespace
+{
+
+const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+}
+
+// Functor to test whether a Finish signal is emitted
+struct TransitionFinishCheck
+{
+  TransitionFinishCheck(bool& signalReceived)
+  : mSignalReceived(signalReceived)
+  {
+  }
+
+  void operator()(TransitionSet& transitionSet)
+  {
+    mSignalReceived = true;
+  }
+
+  void Reset()
+  {
+    mSignalReceived = false;
+  }
+
+  void CheckSignalReceived()
+  {
+    if(!mSignalReceived)
+    {
+      tet_printf("Expected Finish signal was not received\n");
+      tet_result(TET_FAIL);
+    }
+    else
+    {
+      tet_result(TET_PASS);
+    }
+  }
+
+  void CheckSignalNotReceived()
+  {
+    if(mSignalReceived)
+    {
+      tet_printf("Unexpected Finish signal was received\n");
+      tet_result(TET_FAIL);
+    }
+    else
+    {
+      tet_result(TET_PASS);
+    }
+  }
+
+  bool& mSignalReceived; // owned by individual tests
+};
+
+int UtcDaliTransitionSetGetProperty01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionSetGetProperty01");
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 50.f);
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, Vector3(50, 50, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.0f, 0.5f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 30.f);
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(-0.1f, -0.1f));
+  TimePeriod timePeriod = transition.GetTimePeriod();
+  DALI_TEST_EQUALS(0.0f, timePeriod.durationSeconds, TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, timePeriod.delaySeconds, TEST_LOCATION);
+
+  transition.SetTimePeriod(TimePeriod(0.5f, 1.0f));
+  timePeriod = transition.GetTimePeriod();
+  DALI_TEST_EQUALS(1.0f, timePeriod.durationSeconds, TEST_LOCATION);
+  DALI_TEST_EQUALS(0.5f, timePeriod.delaySeconds, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Dali::AlphaFunction::DEFAULT, transition.GetAlphaFunction().GetBuiltinFunction(), TEST_LOCATION);
+  transition.SetAlphaFunction(Dali::AlphaFunction::EASE_IN_OUT);
+  DALI_TEST_EQUALS(Dali::AlphaFunction::EASE_IN_OUT, transition.GetAlphaFunction().GetBuiltinFunction(), TEST_LOCATION);
+
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+
+  DALI_TEST_EQUALS(1, transitionSet.GetTransitionCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(transition, transitionSet.GetTransitionAt(0), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionSetGetProperty02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionSetGetProperty02");
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, Vector4(50.0f, 30.0f, 40.0f, 20.0f));
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, Vector3(50, 50, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.0f, 0.5f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, Vector4(32.f, 54.0f, 24.0f, 42.0f));
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(-0.1f));
+  TimePeriod timePeriod = transition.GetTimePeriod();
+  DALI_TEST_EQUALS(0.0f, timePeriod.durationSeconds, TEST_LOCATION);
+  DALI_TEST_EQUALS(0.0f, timePeriod.delaySeconds, TEST_LOCATION);
+
+  transition.SetTimePeriod(TimePeriod(0.5f, 1.0f));
+  timePeriod = transition.GetTimePeriod();
+  DALI_TEST_EQUALS(1.0f, timePeriod.durationSeconds, TEST_LOCATION);
+  DALI_TEST_EQUALS(0.5f, timePeriod.delaySeconds, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(Dali::AlphaFunction::DEFAULT, transition.GetAlphaFunction().GetBuiltinFunction(), TEST_LOCATION);
+  transition.SetAlphaFunction(Dali::AlphaFunction::EASE_IN_OUT);
+  DALI_TEST_EQUALS(Dali::AlphaFunction::EASE_IN_OUT, transition.GetAlphaFunction().GetBuiltinFunction(), TEST_LOCATION);
+
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+
+  DALI_TEST_EQUALS(1, transitionSet.GetTransitionCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(transition, transitionSet.GetTransitionAt(0), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPair(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPair");
+
+  Vector3 destinationPosition(50, 50, 0);
+  Vector3 destinationSize(120, 120, 0);
+  Vector3 destinationScale(2, 1, 0);
+  Vector4 destinationColor(1.0f, 0.5f, 1.0f, 0.8f);
+  float destinationOpacity(0.8f);
+  float destinationRadius(50.f);
+  Vector4 destinationRadiusV4 = Vector4(destinationRadius, destinationRadius, destinationRadius, destinationRadius);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  control1.SetProperty(Actor::Property::SCALE, Vector3(1, 2, 0));
+  control1.SetProperty(Actor::Property::COLOR, Vector4(1.0f, 1.0f, 1.0f, 0.5f));
+  control1.SetProperty(Actor::Property::OPACITY, 0.5f);
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 30.f);
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, destinationPosition);
+  control2.SetProperty(Actor::Property::SIZE, destinationSize);
+  control2.SetProperty(Actor::Property::SCALE, destinationScale);
+  control2.SetProperty(Actor::Property::COLOR, destinationColor);
+  control2.SetProperty(Actor::Property::OPACITY, destinationOpacity);
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.0f, 0.5f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, destinationRadius);
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+  Property::Map backgroundMap = control2.GetProperty<Property::Map>(Toolkit::Control::Property::BACKGROUND);
+  Vector4 cornerRadius = backgroundMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+  DALI_TEST_EQUALS(destinationRadiusV4, cornerRadius, TEST_LOCATION);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(50);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  DALI_TEST_NOT_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), 0.00001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(1, control2.GetRendererCount(), TEST_LOCATION);
+  Dali::Renderer renderer = control2.GetRendererAt(0);
+  Property::Index index = renderer.GetPropertyIndex(DevelVisual::Property::CORNER_RADIUS);
+  cornerRadius = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_NOT_EQUALS(destinationRadiusV4, cornerRadius, 0.00001f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(700);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationSize, control2.GetCurrentProperty<Vector3>(Actor::Property::SIZE), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationScale, control2.GetCurrentProperty<Vector3>(Actor::Property::SCALE), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationColor, control2.GetCurrentProperty<Vector4>(Actor::Property::COLOR), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationOpacity, control2.GetCurrentProperty<float>(Actor::Property::OPACITY), TEST_LOCATION);
+  DALI_TEST_EQUALS(1, control2.GetRendererCount(), TEST_LOCATION);
+  renderer = control2.GetRendererAt(0);
+  index = renderer.GetPropertyIndex(DevelVisual::Property::CORNER_RADIUS);
+  cornerRadius = renderer.GetCurrentProperty<Vector4>(index);
+  DALI_TEST_EQUALS(destinationRadiusV4, cornerRadius, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPairWithoutEmptySourceBackground(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPair");
+
+  Vector4 destinationRadius(50.f, 30.f, 40.f, 0.f);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, Vector3(50, 50, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.0f, 0.5f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, destinationRadius);
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  Property::Map backgroundMap = control2.GetProperty<Property::Map>(Toolkit::Control::Property::BACKGROUND);
+  Vector4 cornerRadius = backgroundMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+  DALI_TEST_EQUALS(destinationRadius, cornerRadius, TEST_LOCATION);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(50);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  backgroundMap = control2.GetProperty<Property::Map>(Toolkit::Control::Property::BACKGROUND);
+  cornerRadius = backgroundMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+  DALI_TEST_EQUALS(destinationRadius, cornerRadius, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(700);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  backgroundMap = control2.GetProperty<Property::Map>(Toolkit::Control::Property::BACKGROUND);
+  cornerRadius = backgroundMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+  DALI_TEST_EQUALS(destinationRadius, cornerRadius, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenImageViewPair(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPair");
+
+  Vector3 destinationPosition(50, 50, 0);
+
+  ImageView control1 = ImageView::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
+  controlProperty1.Insert(Toolkit::ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  controlProperty1.Insert(Toolkit::Visual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.5f, 0.5f));
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 50.f);
+  control1.SetProperty(Toolkit::ImageView::Property::IMAGE, controlProperty1);
+
+  ImageView control2 = ImageView::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, destinationPosition);
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
+  controlProperty2.Insert(Toolkit::ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  controlProperty2.Insert(Toolkit::Visual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 1.0f, 1.0f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 30.f);
+  control2.SetProperty(Toolkit::ImageView::Property::IMAGE, controlProperty2);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Vector3 startWorldPosition = control1.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+  Vector3 finishWorldPosition = control2.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(400);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  // control2 moved about 80%
+  Vector3 currentPosition = control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
+  Vector3 expectedPosition_0_7 = startWorldPosition + (finishWorldPosition - startWorldPosition) * 0.7;
+  Vector3 expectedPosition_0_9 = startWorldPosition + (finishWorldPosition - startWorldPosition) * 0.9;
+  DALI_TEST_CHECK(currentPosition.x <= expectedPosition_0_7.x && currentPosition.x >= expectedPosition_0_9.x);
+  DALI_TEST_CHECK(currentPosition.y <= expectedPosition_0_7.y && currentPosition.y >= expectedPosition_0_9.y);
+
+  application.SendNotification();
+  application.Render(200);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  DALI_TEST_NOT_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), 0.00001f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenImageViewPairWithDelay(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPair");
+
+  Vector3 destinationPosition(50, 50, 0);
+
+  ImageView control1 = ImageView::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
+  controlProperty1.Insert(Toolkit::ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  controlProperty1.Insert(Toolkit::Visual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 0.5f, 0.5f));
+  controlProperty1.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 50.f);
+  control1.SetProperty(Toolkit::ImageView::Property::IMAGE, controlProperty1);
+
+  ImageView control2 = ImageView::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, destinationPosition);
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
+  controlProperty2.Insert(Toolkit::ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  controlProperty2.Insert(Toolkit::Visual::Property::MIX_COLOR, Vector4(1.0f, 1.0f, 1.0f, 1.0f));
+  controlProperty2.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, 30.f);
+  control2.SetProperty(Toolkit::ImageView::Property::IMAGE, controlProperty2);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Vector3 startWorldPosition = control1.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+  Vector3 finishWorldPosition = control2.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f, 0.5f));
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(400);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  DALI_TEST_EQUALS(startWorldPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+
+
+  application.SendNotification();
+  application.Render(400);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalNotReceived();
+
+  // control2 moved about 60% (800ms)
+  Vector3 currentPosition = control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
+  Vector3 expectedPosition_0_5 = startWorldPosition + (finishWorldPosition - startWorldPosition) * 0.5;
+  Vector3 expectedPosition_0_7 = startWorldPosition + (finishWorldPosition - startWorldPosition) * 0.7;
+  DALI_TEST_CHECK(currentPosition.x <= expectedPosition_0_5.x && currentPosition.x >= expectedPosition_0_7.x);
+  DALI_TEST_CHECK(currentPosition.y <= expectedPosition_0_5.y && currentPosition.y >= expectedPosition_0_7.y);
+
+  application.SendNotification();
+  application.Render(400);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  DALI_TEST_NOT_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), 0.00001f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPairWithTree(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPairWithTree");
+
+  Vector3 destinationPosition(50, 50, 0);
+  Vector3 destinationWorldPosition(-130, -290, 0);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, destinationPosition);
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  Control control3 = Control::New();
+  control3.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control3.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control3.SetProperty(Actor::Property::POSITION, Vector3(50, 50, 0));
+  control3.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty3;
+  controlProperty3.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty3.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control3.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty3);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+  control2.Add(control3);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(600);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(destinationPosition, control2.GetCurrentProperty<Vector3>(Actor::Property::POSITION), TEST_LOCATION);
+  DALI_TEST_EQUALS(destinationWorldPosition, control2.GetProperty<Vector3>(Actor::Property::WORLD_POSITION), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPairWithTreeWithChild(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPairWithTreeWithChild");
+
+  Vector3 destinationWorldPosition(-80, -240, 0);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::POSITION, Vector3(100, 200, 0));
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  control2.SetProperty(Actor::Property::POSITION, Vector3(50, 50, 0));
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  Control control3 = Control::New();
+  control3.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control3.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control3.SetProperty(Actor::Property::POSITION, Vector3(50, 50, 0));
+  control3.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty3;
+  controlProperty3.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty3.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control3.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty3);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+  control2.Add(control3);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition = Transition::New(control1, control2, TimePeriod(0.5f));
+  transition.TransitionWithChild(true);
+  TransitionSet transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(600);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(destinationWorldPosition, control3.GetProperty<Vector3>(Actor::Property::WORLD_POSITION), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPairWithTreeWithoutPositionInheritance(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPairWithTreeWithoutPositionInheritance");
+
+  Vector3 sourcePosition(50, 50, 0);
+  Vector3 destinationPosition(100, 100, 0);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control1.SetProperty(Actor::Property::POSITION, sourcePosition);
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control2.SetProperty(Actor::Property::POSITION, Vector3(150, 150, 0));
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  Control control3 = Control::New();
+  control3.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control3.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control3.SetProperty(Actor::Property::POSITION, destinationPosition);
+  control3.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty3;
+  controlProperty3.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty3.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control3.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty3);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+  control2.Add(control3);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Transition transition;
+  TransitionSet transitionSet;
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+
+  // not inherit Position.
+  control3.SetProperty(Actor::Property::INHERIT_POSITION, false);
+  control3.SetProperty(Actor::Property::INHERIT_ORIENTATION, true);
+  control3.SetProperty(Actor::Property::INHERIT_SCALE, true);
+
+  transition = Transition::New(control1, control3, TimePeriod(0.5f));
+  transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(300);
+
+  Vector3 currentPosition = control3.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+  DALI_TEST_CHECK(currentPosition.x <= destinationPosition.x && currentPosition.x >= sourcePosition.x);
+  DALI_TEST_CHECK(currentPosition.y <= destinationPosition.y && currentPosition.y >= sourcePosition.y);
+  DALI_TEST_CHECK(currentPosition.z <= destinationPosition.z && currentPosition.z >= sourcePosition.z);
+
+  application.SendNotification();
+  application.Render(300);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  DALI_TEST_EQUALS(destinationPosition, control3.GetProperty<Vector3>(Actor::Property::WORLD_POSITION), TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPairWithTreeWithoutOrientationInheritance(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPairWithTreeWithoutOrientationInheritance");
+
+  Radian sourceAngle(1.0f);
+  Radian destinationAngle(2.0f);
+  Quaternion sourceOrientation(sourceAngle, Vector3::XAXIS);
+  Quaternion destinationOrientation(destinationAngle, Vector3::XAXIS);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control1.SetProperty(Actor::Property::ORIENTATION, sourceOrientation);
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control2.SetProperty(Actor::Property::ORIENTATION, Quaternion(Radian(2.0f), Vector3::XAXIS));
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  Control control3 = Control::New();
+  control3.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control3.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control3.SetProperty(Actor::Property::ORIENTATION, destinationOrientation);
+  control3.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty3;
+  controlProperty3.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty3.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control3.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty3);
+
+  // not inherit Orientation.
+  control3.SetProperty(Actor::Property::INHERIT_POSITION, true);
+  control3.SetProperty(Actor::Property::INHERIT_ORIENTATION, false);
+  control3.SetProperty(Actor::Property::INHERIT_SCALE, true);
+
+  Vector3 currentAxis;
+  Radian currentRadian;
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+  control2.Add(control3);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Quaternion currentOrientation = control3.GetProperty<Quaternion>(Actor::Property::WORLD_ORIENTATION);
+  DALI_TEST_EQUALS(currentOrientation, destinationOrientation, 0.0001f, TEST_LOCATION);
+
+  Transition transition;
+  TransitionSet transitionSet;
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+
+  transition = Transition::New(control1, control3, TimePeriod(0.5f));
+  transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(300);
+
+  currentOrientation = control3.GetProperty<Quaternion>(Actor::Property::WORLD_ORIENTATION);
+  DALI_TEST_NOT_EQUALS(currentOrientation, destinationOrientation, 0.0001f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(300);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  currentOrientation = control3.GetProperty<Quaternion>(Actor::Property::WORLD_ORIENTATION);
+  DALI_TEST_EQUALS(currentOrientation, destinationOrientation, 0.0001f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionBetweenControlPairWithTreeWithoutScaleInheritance(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTransitionBetweenControlPairWithTreeWithoutOrientationInheritance");
+
+  Vector3 sourceScale(1, 1, 1);
+  Vector3 destinationScale(2, 2, 1);
+
+  Control control1 = Control::New();
+  control1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control1.SetProperty(Actor::Property::SCALE, sourceScale);
+  control1.SetProperty(Actor::Property::SIZE, Vector3(150, 150, 0));
+  Property::Map controlProperty1;
+  controlProperty1.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control1.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty1);
+
+  Control control2 = Control::New();
+  control2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control2.SetProperty(Actor::Property::SCALE, Vector3(3, 3, 1));
+  control2.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty2;
+  controlProperty2.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control2.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty2);
+
+  Control control3 = Control::New();
+  control3.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  control3.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  control3.SetProperty(Actor::Property::SCALE, destinationScale);
+  control3.SetProperty(Actor::Property::SIZE, Vector3(120, 120, 0));
+  Property::Map controlProperty3;
+  controlProperty3.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+  controlProperty3.Insert(Toolkit::ColorVisual::Property::MIX_COLOR, Vector4(1.0f, 0.0f, 0.0f, 1.0f));
+  control3.SetProperty(Toolkit::Control::Property::BACKGROUND, controlProperty3);
+
+  // not inherit Orientation.
+  control3.SetProperty(Actor::Property::INHERIT_POSITION, true);
+  control3.SetProperty(Actor::Property::INHERIT_ORIENTATION, true);
+  control3.SetProperty(Actor::Property::INHERIT_SCALE, false);
+
+  application.GetScene().Add(control1);
+  application.GetScene().Add(control2);
+  control2.Add(control3);
+
+  application.SendNotification();
+  application.Render(20);
+
+  Vector3 currentScale = control3.GetProperty<Vector3>(Actor::Property::WORLD_SCALE);
+  DALI_TEST_EQUALS(currentScale, destinationScale, 0.0001f, TEST_LOCATION);
+
+  Transition transition;
+  TransitionSet transitionSet;
+  bool signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+
+  transition = Transition::New(control1, control3, TimePeriod(0.5f));
+  transitionSet = TransitionSet::New();
+  transitionSet.AddTransition(transition);
+  transitionSet.Play();
+  transitionSet.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(300);
+
+  currentScale = control3.GetProperty<Vector3>(Actor::Property::WORLD_SCALE);
+  DALI_TEST_CHECK(currentScale.x <= destinationScale.x && currentScale.x >= sourceScale.x);
+  DALI_TEST_CHECK(currentScale.y <= destinationScale.y && currentScale.y >= sourceScale.y);
+  DALI_TEST_CHECK(currentScale.z <= destinationScale.z && currentScale.z >= sourceScale.z);
+
+  application.SendNotification();
+  application.Render(300);
+
+  // We didn't expect the animation to finish yet
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  application.SendNotification();
+  application.Render(20);
+
+  currentScale = control3.GetProperty<Vector3>(Actor::Property::WORLD_SCALE);
+  DALI_TEST_EQUALS(currentScale, destinationScale, 0.0001f, TEST_LOCATION);
+
+  END_TEST;
+}
index a0f5334..5864554 100644 (file)
@@ -502,6 +502,9 @@ int UtcDaliVisualGetPropertyMap1(void)
   propertyMap.Insert(Visual::Property::MIX_COLOR,  Color::BLUE);
   propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS, 10.0f );
   propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE );
+  propertyMap.Insert( DevelVisual::Property::BORDERLINE_WIDTH, 20.0f );
+  propertyMap.Insert( DevelVisual::Property::BORDERLINE_COLOR, Color::RED );
+  propertyMap.Insert( DevelVisual::Property::BORDERLINE_OFFSET, -1.0f );
   propertyMap.Insert( DevelColorVisual::Property::BLUR_RADIUS, 20.0f );
   Visual::Base colorVisual = factory.CreateVisual( propertyMap );
 
@@ -524,6 +527,18 @@ int UtcDaliVisualGetPropertyMap1(void)
   DALI_TEST_CHECK( cornerRadiusPolicyValue );
   DALI_TEST_CHECK( cornerRadiusPolicyValue->Get< int >() == Toolkit::Visual::Transform::Policy::RELATIVE );
 
+  Property::Value* borderlineWidthValue = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+  DALI_TEST_CHECK( borderlineWidthValue );
+  DALI_TEST_CHECK( borderlineWidthValue->Get< float >() == 20.0f );
+
+  Property::Value* borderlineColorValue = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( borderlineColorValue );
+  DALI_TEST_CHECK( borderlineColorValue->Get< Vector4 >() == Color::RED );
+
+  Property::Value* borderlineOffsetValue = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( borderlineOffsetValue );
+  DALI_TEST_CHECK( borderlineOffsetValue->Get< float >() == -1.0f );
+
   Property::Value* blurRadiusValue = resultMap.Find( DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT );
   DALI_TEST_CHECK( blurRadiusValue );
   DALI_TEST_CHECK( blurRadiusValue->Get< float >() == 20.0f );
@@ -599,10 +614,23 @@ int UtcDaliVisualGetPropertyMap2(void)
   DALI_TEST_CHECK( colorValue );
   DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::CYAN );
 
-  colorValue = resultMap.Find( BorderVisual::Property::SIZE,  Property::FLOAT );
+  sizeValue = resultMap.Find( BorderVisual::Property::SIZE,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 10.f );
+
+  // Get default value of borderline values here
+
+  sizeValue = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 0.0f );
+
+  colorValue = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR,  Property::VECTOR4 );
   DALI_TEST_CHECK( colorValue );
-  DALI_TEST_CHECK( colorValue->Get<float>() == 10.f );
+  DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::BLACK );
 
+  sizeValue = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 0.0f );
 
   END_TEST;
 }
@@ -655,6 +683,11 @@ int UtcDaliVisualGetPropertyMap3(void)
   stopColors.PushBack( Color::GREEN );
   propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
 
+  float borderlineWidth = 4.0f;
+  Vector4 cornerRadius(7.0f, 10.0f, 13.0f, 16.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH,  borderlineWidth);
+  propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS,  cornerRadius);
+
   Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
 
   Property::Map resultMap;
@@ -681,6 +714,14 @@ int UtcDaliVisualGetPropertyMap3(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<Vector2>(), end , Math::MACHINE_EPSILON_100, TEST_LOCATION );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH,   Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), borderlineWidth , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::CORNER_RADIUS,   Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), cornerRadius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
   value = resultMap.Find( GradientVisual::Property::STOP_OFFSET,   Property::ARRAY );
   DALI_TEST_CHECK( value );
   Property::Array* offsetArray = value->GetArray();
@@ -722,6 +763,11 @@ int UtcDaliVisualGetPropertyMap4(void)
   stopColors.PushBack( Color::GREEN );
   propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
 
+  float borderlineWidth = 8.0f;
+  Vector4 cornerRadius(1.0f, 2.0f, 4.0f, 8.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH,  borderlineWidth);
+  propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS,  cornerRadius);
+
   Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
   DALI_TEST_CHECK( gradientVisual );
 
@@ -749,6 +795,14 @@ int UtcDaliVisualGetPropertyMap4(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<float>(), radius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH,   Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), borderlineWidth , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::CORNER_RADIUS,   Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), cornerRadius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
   value = resultMap.Find( GradientVisual::Property::STOP_OFFSET,   Property::ARRAY );
   DALI_TEST_CHECK( value );
   Property::Array* offsetArray = value->GetArray();
@@ -3910,6 +3964,361 @@ int UtcDaliVisualRoundedCorner(void)
   END_TEST;
 }
 
+int UtcDaliVisualBorderline(void)
+{
+#ifdef OLD_GRAPHICS_TEST
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualBorderline" );
+
+  static std::vector<UniformData> customUniforms =
+  {
+    UniformData("cornerRadius", Property::Type::VECTOR4),
+    UniformData("cornerRadiusPolicy", Property::Type::FLOAT),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineColor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
+  };
+
+  TestGraphicsController& graphics = application.GetGraphicsController();
+  graphics.AddCustomUniforms(customUniforms);
+
+  // image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float cornerRadius = 5.0f;
+    float borderlineWidth = 30.0f;
+    Vector4 borderlineColor(1.0f, 0.0f, 0.0f, 1.0f);
+    float borderlineOffset = 1.0f;
+
+    properties[Visual::Property::TYPE] = Visual::IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties[DevelVisual::Property::BORDERLINE_COLOR] = borderlineColor;
+    properties[DevelVisual::Property::BORDERLINE_OFFSET] = borderlineOffset;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius) ), true, TEST_LOCATION );
+    // Default corner radius policy is absolute.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // color visual 1
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    Vector4 cornerRadius(23.0f, 2.0f, 3.0f, 2.3f);
+    float borderlineWidth = 30.0f;
+    Vector4 borderlineColor(0.5f, 0.4f, 0.3f, 0.2f);
+    float borderlineOffset = -0.4f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties["cornerRadius"] = cornerRadius;
+    properties["borderlineWidth"] = borderlineWidth;
+    properties["borderlineColor"] = borderlineColor;
+    properties["borderlineOffset"] = borderlineOffset;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // color visual 2, default color, default offset
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 30.0f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    // Default borderline color is BLACK.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+    // Default borderline offset is 0.0f.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+  }
+
+  // color visual 3, offset not [-1.0 ~ 1.0], but uniform value is same anyway
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 30.0f;
+    Vector4 borderlineColor(0.5f, 0.4f, 0.3f, 0.2f);
+    float borderlineOffset = 37.4f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties["borderlineWidth"] = borderlineWidth;
+    properties["borderlineColor"] = borderlineColor;
+    properties["borderlineOffset"] = borderlineOffset;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    // NOTE : borderlineOffset will clamp in fragment shader. not visual itself
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // gradient visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 30.0f;
+    float cornerRadius = 70.0f;
+
+    properties[Visual::Property::TYPE] = Visual::GRADIENT;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties[GradientVisual::Property::START_POSITION] = Vector2( 0.5f, 0.5f );
+    properties[GradientVisual::Property::END_POSITION] = Vector2( -0.5f, -0.5f );
+    properties[GradientVisual::Property::UNITS] = GradientVisual::Units::USER_SPACE;
+
+    Property::Array stopOffsets;
+    stopOffsets.PushBack( 0.0f );
+    stopOffsets.PushBack( 0.6f );
+    stopOffsets.PushBack( 1.0f );
+    properties[GradientVisual::Property::STOP_OFFSET] = stopOffsets;
+
+    Property::Array stopColors;
+    stopColors.PushBack( Color::RED );
+    stopColors.PushBack( Color::YELLOW );
+    stopColors.PushBack( Color::GREEN );
+    properties[GradientVisual::Property::STOP_COLOR] = stopColors;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius) ), true, TEST_LOCATION );
+    // Default corner radius policy is absolute.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    // Default borderline color is BLACK.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+    // Default borderline offset is 0.0f.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+  }
+
+  // animated image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 24.0f;
+    float borderlineOffset = -1.0f;
+
+    properties[Visual::Property::TYPE] = Visual::ANIMATED_IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_GIF_FILE_NAME;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth + 10.0f; // Dummy Input
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties["borderlineOffset"] = borderlineOffset;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    // Default borderline color is BLACK.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // vector image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    Vector4 cornerRadius(54.0f, 43.0f, 32.0f, 21.0f);
+    float borderlineWidth = 27.0f;
+    Vector4 borderlineColor(0.5f, 0.5f, 0.5f, 0.0f);
+
+    properties[Visual::Property::TYPE] = Visual::SVG;
+    properties[ImageVisual::Property::URL] = TEST_SVG_FILE_NAME;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties[DevelVisual::Property::BORDERLINE_COLOR] = borderlineColor;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+    // Default corner radius policy is absolute.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    // Default borderline offset is 0.0.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+  }
+
+  // animated vector image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    Vector4 cornerRadius(1.3f, 0.0f, 0.4f, 0.2f);
+    float borderlineWidth = 13.0f;
+    Vector4 borderlineColor(0.3f, 0.3f, 0.3f, 1.0f);
+    float borderlineOffset = 13.0f;
+
+    properties[Visual::Property::TYPE] = DevelVisual::ANIMATED_VECTOR_IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_VECTOR_IMAGE_FILE_NAME;
+    properties["cornerRadius"] = cornerRadius;
+    properties[DevelVisual::Property::CORNER_RADIUS_POLICY] = Toolkit::Visual::Transform::Policy::RELATIVE;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties["borderlineColor"] = borderlineColor;
+    properties[DevelVisual::Property::BORDERLINE_OFFSET] = borderlineOffset;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::RELATIVE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+#else
+  tet_result(TET_PASS);
+#endif
+
+  END_TEST;
+}
+
+
 int UtcDaliColorVisualBlurRadius(void)
 {
   ToolkitTestApplication application;
@@ -4101,6 +4510,9 @@ int UtcDaliVisualGetVisualProperty01(void)
     UniformData("size", Property::Type::VECTOR2),
     UniformData("cornerRadius", Property::Type::VECTOR4),
     UniformData("blurRadius", Property::Type::FLOAT),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineColor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
   };
 
   TestGraphicsController& graphics = application.GetGraphicsController();
@@ -4113,6 +4525,9 @@ int UtcDaliVisualGetVisualProperty01(void)
   propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, Vector4(10.0f, 0.0f, 2.0f, 4.0f));
   propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE);
   propertyMap.Insert(DevelColorVisual::Property::BLUR_RADIUS, 20.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 20.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_COLOR, Color::RED);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_OFFSET, 1.0f);
   Visual::Base colorVisual = factory.CreateVisual(propertyMap);
 
   DummyControl dummyControl = DummyControl::New(true);
@@ -4130,6 +4545,9 @@ int UtcDaliVisualGetVisualProperty01(void)
   float targetOpacity = 0.5f;
   Vector4 targetCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
   float targetBlurRadius = 10.0f;
+  float targetBorderlineWidth = 25.0f;
+  Vector4 targetBorderlineColor(1.0f, 1.0f, 1.0f, 1.0f);
+  float targetBorderlineOffset = -1.0f;
 
   Animation animation = Animation::New(1.0f);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::MIX_COLOR), targetColor);
@@ -4138,6 +4556,9 @@ int UtcDaliVisualGetVisualProperty01(void)
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Transform::Property::SIZE), targetSize);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), targetCornerRadius);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelColorVisual::Property::BLUR_RADIUS), targetBlurRadius);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), targetBorderlineWidth);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), targetBorderlineColor);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_OFFSET), targetBorderlineOffset);
   animation.Play();
 
   application.SendNotification();
@@ -4172,12 +4593,27 @@ int UtcDaliVisualGetVisualProperty01(void)
   DALI_TEST_CHECK(blurRadiusValue);
   DALI_TEST_EQUALS(blurRadiusValue->Get< float >(), targetBlurRadius, TEST_LOCATION);
 
+  Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineWidthValue);
+  DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+  Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+  DALI_TEST_CHECK(borderlineColorValue);
+  DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+  Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineOffsetValue);
+  DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
   // Test uniform values
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", targetColor), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector2>("offset", targetOffset), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector2>("size", targetSize), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("cornerRadius", targetCornerRadius), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("blurRadius", targetBlurRadius), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineWidth", targetBorderlineWidth), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("borderlineColor", targetBorderlineColor), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineOffset", targetBorderlineOffset), true, TEST_LOCATION);
 
   // Test not-supported property
   Property property1 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::PREMULTIPLIED_ALPHA);
@@ -4203,6 +4639,9 @@ int UtcDaliVisualGetVisualProperty02(void)
     UniformData("offset", Property::Type::VECTOR2),
     UniformData("size", Property::Type::VECTOR2),
     UniformData("cornerRadius", Property::Type::VECTOR4),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineCOlor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
     UniformData("blurRadius", Property::Type::FLOAT),
   };
 
@@ -4228,6 +4667,9 @@ int UtcDaliVisualGetVisualProperty02(void)
   Vector2 targetSize(1.1f, 1.1f);
   float targetOpacity = 0.5f;
   Vector4 targetCornerRadius(20.0f, 0.0f, 20.0f, 0.0f);
+  float targetBorderlineWidth = 77.7f;
+  Vector4 targetBorderlineColor(0.4f, 0.2f, 0.3f, 0.9f);
+  float targetBorderlineOffset = 1.0f;
   float targetBlurRadius = 10.0f;
 
   // Should work when the properties are not set before
@@ -4237,6 +4679,9 @@ int UtcDaliVisualGetVisualProperty02(void)
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "offset"), targetOffset);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "size"), targetSize);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "cornerRadius"), targetCornerRadius);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineWidth"), targetBorderlineWidth);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineColor"), targetBorderlineColor);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineOffset"), targetBorderlineOffset);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "blurRadius"), targetBlurRadius);
   animation.Play();
 
@@ -4268,6 +4713,18 @@ int UtcDaliVisualGetVisualProperty02(void)
   DALI_TEST_CHECK(cornerRadiusValue);
   DALI_TEST_EQUALS(cornerRadiusValue->Get< Vector4 >(), targetCornerRadius, TEST_LOCATION);
 
+  Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineWidthValue);
+  DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+  Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+  DALI_TEST_CHECK(borderlineColorValue);
+  DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+  Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineOffsetValue);
+  DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
   Property::Value* blurRadiusValue = resultMap.Find(DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT);
   DALI_TEST_CHECK(blurRadiusValue);
   DALI_TEST_EQUALS(blurRadiusValue->Get< float >(), targetBlurRadius, TEST_LOCATION);
@@ -4288,11 +4745,14 @@ int UtcDaliVisualGetVisualProperty03(void)
 {
 #ifdef OLD_GRAPHICS_TEST
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualGetVisualProperty01: Test animatable property, ImageVisual" );
+  tet_infoline( "UtcDaliVisualGetVisualProperty03: Test animatable property, ImageVisual" );
 
   static std::vector<UniformData> customUniforms =
   {
     UniformData("cornerRadius", Property::Type::VECTOR4),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineColor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
   };
 
   TestGraphicsController& graphics = application.GetGraphicsController();
@@ -4302,6 +4762,10 @@ int UtcDaliVisualGetVisualProperty03(void)
   Property::Map propertyMap;
   propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
   propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  //We must set some value because application cannot notify shader changed
+  propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, 1.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+
   Visual::Base imageVisual = factory.CreateVisual(propertyMap);
 
   DummyControl dummyControl = DummyControl::New(true);
@@ -4318,10 +4782,16 @@ int UtcDaliVisualGetVisualProperty03(void)
 
   float targetOpacity = 0.5f;
   Vector4 targetCornerRadius(20.0f, 20.0f, 0.0f, 0.0f);
+  float targetBorderlineWidth = 10.0f;
+  Vector4 targetBorderlineColor(1.0f, 0.0f, 1.0f, 0.5f);
+  float targetBorderlineOffset = -1.5f;
 
   Animation animation = Animation::New(1.0f);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::OPACITY), targetOpacity);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), targetCornerRadius);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), targetBorderlineWidth);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), targetBorderlineColor);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_OFFSET), targetBorderlineOffset);
   animation.Play();
 
   application.SendNotification();
@@ -4340,8 +4810,23 @@ int UtcDaliVisualGetVisualProperty03(void)
   DALI_TEST_CHECK(cornerRadiusValue);
   DALI_TEST_EQUALS(cornerRadiusValue->Get< Vector4 >(), targetCornerRadius, TEST_LOCATION);
 
+  Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineWidthValue);
+  DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+  Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+  DALI_TEST_CHECK(borderlineColorValue);
+  DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+  Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineOffsetValue);
+  DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
   // Test uniform value
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("cornerRadius", targetCornerRadius), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineWidth", targetBorderlineWidth), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("borderlineColor", targetBorderlineColor), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineOffset", targetBorderlineOffset), true, TEST_LOCATION);
 #else
   tet_result(TET_PASS);
 #endif
index 8756121..fd3e72e 100644 (file)
@@ -266,6 +266,23 @@ static Dali::Actor CreateHighlightIndicatorActor()
   return actor;
 }
 
+void AccessibleImpl::ScrollToSelf()
+{
+  auto* child = this;
+  auto* parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(child->GetParent());
+
+  while (parent)
+  {
+    if (parent->IsScrollable())
+    {
+      parent->ScrollToChild(child->Self());
+    }
+
+    child = parent;
+    parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(parent->GetParent());
+  }
+}
+
 bool AccessibleImpl::GrabHighlight()
 {
   Dali::Actor self = Self();
@@ -295,7 +312,7 @@ bool AccessibleImpl::GrabHighlight()
   // Remember the highlight actor, so that when the default is changed with
   // SetHighlightActor(), the currently displayed highlight can still be cleared.
   currentHighlightActor = highlight;
-  EnsureSelfVisible();
+  ScrollToSelf();
   self.Add(highlight);
   SetCurrentlyHighlightedActor(self);
   EmitHighlighted(true);
@@ -402,17 +419,9 @@ std::vector<Dali::Accessibility::Relation> AccessibleImpl::GetRelationSet()
   return ret;
 }
 
-void AccessibleImpl::EnsureChildVisible(Actor child)
-{
-}
-
-void AccessibleImpl::EnsureSelfVisible()
+bool AccessibleImpl::ScrollToChild(Actor child)
 {
-  auto parent = dynamic_cast<AccessibleImpl*>(GetParent());
-  if(parent)
-  {
-    parent->EnsureChildVisible(Self());
-  }
+  return false;
 }
 
 Dali::Property::Index AccessibleImpl::GetNamePropertyIndex()
index ed09487..ab168c6 100644 (file)
@@ -62,6 +62,8 @@ protected:
     return handle;
   }
 
+  void ScrollToSelf();
+
 public:
   AccessibleImpl(Dali::Actor self, Dali::Accessibility::Role role, bool modal = false);
 
@@ -207,14 +209,9 @@ public:
 
   /**
    * @brief Makes sure that a given child of this container (e.g. ItemView) is visible
+   * @return false if scrolling is not supported or child is already visible
    */
-  virtual void EnsureChildVisible(Actor child);
-
-  /**
-   * @brief Makes sure this actor is visible (when moving the highlight frame to an
-   * actor that is scrolled out of the viewport)
-   */
-  virtual void EnsureSelfVisible();
+  virtual bool ScrollToChild(Actor child);
 
   /**
    * @brief Returns the index of the property that represents this actor's name
index 157051b..487aa1b 100644 (file)
@@ -122,6 +122,19 @@ Dali::Property GetVisualProperty(Control control, Dali::Property::Index index, D
   return controlDataImpl.GetVisualProperty(index, visualPropertyKey);
 }
 
+void CreateTransitions(Control control, Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod)
+{
+  if(animation)
+  {
+    // make visual transition of control visual.
+    Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(internalControl);
+    controlDataImpl.MakeVisualTransition(animation, source, Toolkit::Control::Property::BACKGROUND, alphaFunction, timePeriod);
+    controlDataImpl.MakeVisualTransition(animation, source, Toolkit::DevelControl::Property::SHADOW, alphaFunction, timePeriod);
+    internalControl.OnCreateTransitions(animation, source, alphaFunction, timePeriod);
+  }
+}
+
 static Toolkit::Internal::Control::Impl* GetControlImplementationIfAny(Dali::Actor actor)
 {
   Dali::Toolkit::Control c = Toolkit::Control::DownCast(actor);
index 4978e4d..d977c34 100644 (file)
@@ -20,6 +20,8 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/accessibility-impl.h>
 #include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/animation/time-period.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/accessible-impl.h>
@@ -362,6 +364,20 @@ DALI_TOOLKIT_API VisualEventSignalType& VisualEventSignal(Control control);
 DALI_TOOLKIT_API Dali::Property GetVisualProperty(Control control, Dali::Property::Index index, Dali::Property::Key visualPropertyKey);
 
 /**
+ * @brief Retrieve visual/renderer property animation between this Control and source control.
+ * Input animation must be created before this method called.
+ * And the animations between this method created are added the input animation.
+ * This method generates visual/renderer property animation but not creates Actor property animation.
+ *
+ * @param[in] control The control
+ * @param[in] animation generated animation
+ * @param[in] source source control of the animation.
+ * @param[in] alphaFunction AlphaFunction of the animation
+ * @param[in] timePeriod TimePeriod of the animation
+ */
+DALI_TOOLKIT_API void CreateTransitions(Control control, Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod);
+
+/**
  * @brief The signal is emmited as a succession of "activate" signal send by accessibility client.
  * @return The signal to connect to
  */
index d19c90b..a7349fe 100644 (file)
@@ -55,7 +55,8 @@ enum class Justification
   CENTER,        ///< Items are positioned at the center of the container
   FLEX_END,      ///< Items are positioned at the end of the container
   SPACE_BETWEEN, ///< Items are positioned with equal space between the items
-  SPACE_AROUND   ///< Items are positioned with equal space before, between, and after the items
+  SPACE_AROUND,  ///< Items are positioned with equal space before, and after the items
+  SPACE_EVENLY   ///< Items are positioned with equal space before, between, and after the items
 };
 
 /**
index 1098b7d..ddb02d5 100644 (file)
@@ -94,6 +94,28 @@ enum Type
    *       If it it RELATIVE, the corner radius value is relative to the smaller of the visual width and visual height.
    */
   CORNER_RADIUS_POLICY = OPACITY + 3,
+
+  /**
+   * @brief The width for the borderline of the visual
+   * @details Name "borderlineWidth", type Property::FLOAT, animatable
+   * @note Optional. Default value is 0.0f.
+   */
+  BORDERLINE_WIDTH = OPACITY + 4,
+
+  /**
+   * @brief The color for the borderline of the visual
+   * @details Name "borderlineColor", type Property::VECTOR4, animatable
+   * @note Default value is Color::BLACK
+   */
+  BORDERLINE_COLOR = OPACITY + 5,
+
+  /**
+   * @brief The offset from the visual borderline (recommend [-1.0f to 1.0f]).
+   * @details Name "borderlineOffset", type Property::FLOAT, animatable
+   * @note Default value is 0.0f.
+   * @note This value will be clipped by [-1.0f to 1.0f].
+   */
+  BORDERLINE_OFFSET = OPACITY + 6,
 };
 
 } // namespace Property
index c50cd20..06027de 100644 (file)
@@ -1821,6 +1821,69 @@ Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dal
   return Dali::Property(handle, Property::INVALID_INDEX);
 }
 
+void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod)
+{
+  Dali::Toolkit::Control sourceHandle      = Dali::Toolkit::Control::DownCast(source);
+  Property::Map          sourceMap         = sourceHandle.GetProperty<Property::Map>(visualIndex);
+  Dali::Toolkit::Control destinationHandle = Dali::Toolkit::Control::DownCast(mControlImpl.Self());
+  Property::Map          destinationMap    = destinationHandle.GetProperty<Property::Map>(visualIndex);
+
+  Vector4                  mixColor(1.0f, 1.0f, 1.0f, 1.0f);
+  Vector4                  cornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
+
+  if(!destinationMap.Empty())
+  {
+    mixColor     = destinationMap.Find(Dali::Toolkit::Visual::Property::MIX_COLOR)->Get<Vector4>();
+    cornerRadius = destinationMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+
+    if(sourceMap.Empty())
+    {
+      sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
+      sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT);
+      sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
+    }
+
+    Vector4 sourceMixColor     = sourceMap.Find(Dali::Toolkit::Visual::Property::MIX_COLOR)->Get<Vector4>();
+    Vector4 sourceCornerRadius = sourceMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+
+    std::vector<Dali::Property> properties;
+    std::vector<std::pair<Property::Value, Property::Value>> values;
+
+    if(Vector3(sourceMixColor) != Vector3(mixColor))
+    {
+      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::MIX_COLOR));
+      values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(mixColor)));
+    }
+
+    if(std::abs(sourceMixColor.a - mixColor.a) > Math::MACHINE_EPSILON_1)
+    {
+      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::OPACITY));
+      values.push_back(std::make_pair(sourceMixColor.a, mixColor.a));
+    }
+
+    if(sourceCornerRadius != cornerRadius)
+    {
+      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS));
+      values.push_back(std::make_pair(sourceCornerRadius, cornerRadius));
+    }
+
+    for(uint32_t i = 0; i < properties.size(); ++i)
+    {
+      if(timePeriod.delaySeconds > 0.0f)
+      {
+        Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
+        initialKeyframes.Add(0.0f, values[i].first);
+        initialKeyframes.Add(1.0f, values[i].first);
+        animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
+      }
+      Dali::KeyFrames keyframes = Dali::KeyFrames::New();
+      keyframes.Add(0.0f, values[i].first);
+      keyframes.Add(1.0f, values[i].second);
+      animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
+    }
+  }
+}
+
 void Control::Impl::EmitResourceReadySignal()
 {
   if(!mIsEmittingResourceReadySignal)
index 45430c5..96290b7 100644 (file)
@@ -393,6 +393,18 @@ public:
    */
   Dali::Property GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey);
 
+  /**
+   * @brief Make visual transition from source control to this control about specific Property::Index
+   * If both of source and this control have Property::Index property, than create animation between them.
+   *
+   * @param[in] animation Return animation from source to this control.
+   * @param[in] source Source control to be used property animation.
+   * @param[in] visualIndex Property::Index to make animation.
+   * @param[in] alphaFunction alpha function of the animation.
+   * @param[in] timePeriod time period of the animation.
+   */
+  void MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod);
+
 private:
   /**
    * Used as an alternative to boolean so that it is obvious whether a visual is enabled/disabled.
index 111e480..a3c092d 100644 (file)
@@ -127,7 +127,8 @@ const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
     {"center", Toolkit::FlexContainer::JUSTIFY_CENTER},
     {"flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END},
     {"spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN},
-    {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND}};
+    {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND},
+    {"spaceEvenly", Toolkit::FlexContainer::JUSTIFY_SPACE_EVENLY}};
 const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof(JUSTIFY_CONTENT_STRING_TABLE) / sizeof(JUSTIFY_CONTENT_STRING_TABLE[0]);
 
 const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
index 513960f..031befd 100644 (file)
@@ -287,6 +287,75 @@ void ImageView::OnRelayout(const Vector2& size, RelayoutContainer& container)
   }
 }
 
+void ImageView::OnCreateTransitions(Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod)
+{
+  Dali::Toolkit::ImageView destinationHandle = Toolkit::ImageView(GetOwner());
+  Toolkit::Visual::Base    destinationVisual = DevelControl::GetVisual(GetImplementation(destinationHandle), Toolkit::ImageView::Property::IMAGE);
+  Property::Map            destinationMap;
+
+  if(!destinationVisual)
+  {
+    return;
+  }
+
+  destinationVisual.CreatePropertyMap(destinationMap);
+
+  Vector4 sourceMixColor(0.0f, 0.0f, 0.0f, 0.0f);
+  Vector4 sourceCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
+  Vector4 destinationMixColor     = destinationMap.Find(Dali::Toolkit::Visual::Property::MIX_COLOR)->Get<Vector4>();
+  Vector4 destinationCornerRadius = destinationMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+
+  Dali::Toolkit::ImageView sourceHandle = Dali::Toolkit::ImageView::DownCast(source);
+  Toolkit::Visual::Base    sourceVisual;
+  Property::Map            sourceMap;
+
+  if(sourceHandle)
+  {
+    sourceVisual = DevelControl::GetVisual(GetImplementation(sourceHandle), Toolkit::ImageView::Property::IMAGE);
+  }
+
+  if(sourceVisual)
+  {
+    sourceVisual.CreatePropertyMap(sourceMap);
+    sourceMixColor     = sourceMap.Find(Dali::Toolkit::Visual::Property::MIX_COLOR)->Get<Vector4>();
+    sourceCornerRadius = sourceMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
+  }
+
+  std::vector<Dali::Property> properties;
+  std::vector<std::pair<Property::Value, Property::Value>> values;
+
+  if(Vector3(sourceMixColor) != Vector3(destinationMixColor))
+  {
+    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::MIX_COLOR));
+    values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(destinationMixColor)));
+  }
+  if(std::abs(sourceMixColor.a - destinationMixColor.a) > Math::MACHINE_EPSILON_1)
+  {
+    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::Visual::Property::OPACITY));
+    values.push_back(std::make_pair(sourceMixColor.a, destinationMixColor.a));
+  }
+  if(sourceCornerRadius != destinationCornerRadius)
+  {
+    properties.push_back(DevelControl::GetVisualProperty(destinationHandle, Toolkit::ImageView::Property::IMAGE, Toolkit::DevelVisual::Property::CORNER_RADIUS));
+    values.push_back(std::make_pair(sourceCornerRadius, destinationCornerRadius));
+  }
+
+  for(uint32_t i = 0; i < properties.size(); ++i)
+  {
+    if(timePeriod.delaySeconds > 0.0f)
+    {
+      Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
+      initialKeyframes.Add(0.0f, values[i].first);
+      initialKeyframes.Add(1.0f, values[i].first);
+      animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
+    }
+    Dali::KeyFrames keyframes = Dali::KeyFrames::New();
+    keyframes.Add(0.0f, values[i].first);
+    keyframes.Add(1.0f, values[i].second);
+    animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
+  }
+}
+
 void ImageView::OnResourceReady(Toolkit::Control control)
 {
   // Visual ready so update visual attached to this ImageView, following call to RelayoutRequest will use this visual.
index 90dc192..023930e 100644 (file)
@@ -133,6 +133,11 @@ private: // From Control
    */
   void OnRelayout(const Vector2& size, RelayoutContainer& container) override;
 
+  /**
+   * @copydoc Toolkit::Control::OnCreateTransitions()
+   */
+  virtual void OnCreateTransitions(Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod) override;
+
 private:
   /**
    * @brief Callback for ResourceReadySignal
index ecc25b2..e9b58c8 100644 (file)
@@ -1345,11 +1345,11 @@ void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
   }
 }
 
-void ItemView::AccessibleImpl::EnsureChildVisible(Actor child)
+bool ItemView::AccessibleImpl::ScrollToChild(Actor child)
 {
-  EnsureSelfVisible();
   auto itemView = Dali::Toolkit::ItemView::DownCast(Self());
   Toolkit::GetImpl(itemView).OnKeyboardFocusChangeCommitted(child);
+  return true;
 }
 
 Animation ItemView::DoAnchoring()
index 9b3d656..7e3d8c1 100644 (file)
@@ -438,7 +438,7 @@ protected:
   {
     using Scrollable::AccessibleImpl::AccessibleImpl;
 
-    void EnsureChildVisible(Actor child) override;
+    bool ScrollToChild(Actor child) override;
   };
 
   /**
index ac062ff..8ca6855 100644 (file)
@@ -1823,10 +1823,17 @@ Toolkit::ScrollView::SnapStartedSignalType& ScrollView::SnapStartedSignal()
   return mSnapStartedSignal;
 }
 
-void ScrollView::AccessibleImpl::EnsureChildVisible(Actor child)
+bool ScrollView::AccessibleImpl::ScrollToChild(Actor child)
 {
   auto scrollView = Dali::Toolkit::ScrollView::DownCast(Self());
-  scrollView.ScrollTo(child);
+  if (Toolkit::GetImpl(scrollView).FindClosestActor() == child)
+  {
+    return false;
+  }
+
+  // FIXME: ScrollTo does not work (snaps back to original position)
+  scrollView.ScrollTo(child, scrollView.GetScrollFlickDuration());
+  return true;
 }
 
 void ScrollView::FindAndUnbindActor(Actor child)
index 11ff969..aee050e 100644 (file)
@@ -790,7 +790,7 @@ protected:
   {
     using Scrollable::AccessibleImpl::AccessibleImpl;
 
-    void EnsureChildVisible(Actor child) override;
+    bool ScrollToChild(Actor child) override;
   };
 
   /**
index 3342374..bf85d8d 100755 (executable)
@@ -130,7 +130,8 @@ WebView::WebView(const std::string& locale, const std::string& timezoneId)
   mWebViewArea(0, 0, mWebViewSize.width, mWebViewSize.height),
   mVideoHoleEnabled(true),
   mMouseEventsEnabled(true),
-  mKeyEventsEnabled(true)
+  mKeyEventsEnabled(true),
+  mScreenshotCapturedCallback(nullptr)
 {
   mWebEngine = Dali::WebEngine::New();
 
@@ -154,7 +155,8 @@ WebView::WebView(uint32_t argc, char** argv)
   mWebViewArea(0, 0, mWebViewSize.width, mWebViewSize.height),
   mVideoHoleEnabled(true),
   mMouseEventsEnabled(true),
-  mKeyEventsEnabled(true)
+  mKeyEventsEnabled(true),
+  mScreenshotCapturedCallback(nullptr)
 {
   mWebEngine = Dali::WebEngine::New();
 
index fc8edaf..aabd0c0 100644 (file)
@@ -178,6 +178,10 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/rendering/text-backend-impl.cpp
    ${toolkit_src_dir}/text/rendering/text-typesetter.cpp
    ${toolkit_src_dir}/text/rendering/view-model.cpp
+   ${toolkit_src_dir}/transition/transition-base-impl.cpp
+   ${toolkit_src_dir}/transition/transition-impl.cpp
+   ${toolkit_src_dir}/transition/transition-lifecycle-controller.cpp
+   ${toolkit_src_dir}/transition/transition-set-impl.cpp
    ${toolkit_src_dir}/transition-effects/cube-transition-effect-impl.cpp
    ${toolkit_src_dir}/transition-effects/cube-transition-cross-effect-impl.cpp
    ${toolkit_src_dir}/transition-effects/cube-transition-fold-effect-impl.cpp
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.frag b/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.frag
deleted file mode 100644 (file)
index a3bb80a..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform mediump float blurRadius;
-
-void main()
-{
-  OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 v = abs(vPosition) - vRectSize + radius;
-  mediump float cy = radius + blurRadius;
-  mediump float cr = radius + blurRadius;
-
-  cy = min(cy, min(vRectSize.x, vRectSize.y) - radius);
-  v = vec2(min(v.x, v.y), max(v.x, v.y));
-  v = v + cy;
-
-  mediump float blur = 1.0;
-  mediump float potential = 0.0;
-  mediump float alias = min(radius, 1.0);
-  mediump float potentialMin = cy + radius - blurRadius - alias;
-  mediump float potentialMax = cy + radius + blurRadius + alias;
-
-  // move center of circles for reduce defact
-  mediump float cyDiff = min(cy, 0.2 * blurRadius);
-  cy -= cyDiff;
-  cr += cyDiff;
-
-  mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
-
-  if(diffFromBaseline > 0.0)
-  {
-    // out of calculation bound.
-    potential = v.y;
-
-    // for anti-alias when blurRaidus = 0.0
-    mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
-    mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
-    potentialMin += potentialDiff;
-    potentialMax -= potentialDiff;
-  }
-  else
-  {
-    // get some circle centered (x, x) and radius (r = cr / cy * x)
-    // s.t. point v is on that circle
-    // highest point of that circle is (x, x + r) and potential is x + r
-
-    // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
-
-    mediump float A = (cr * cr - 2.0 * cy * cy);
-    mediump float B = cy * (v.x + v.y);
-    mediump float V = dot(v,v);
-    mediump float D = B * B + A * V;
-    potential = V * (cr + cy) / (sqrt(D) + B);
-  }
-
-  blur = 1.0 - smoothstep(potentialMin, potentialMax, potential);
-  OUT_COLOR.a *= blur;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.vert b/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.vert
deleted file mode 100644 (file)
index 5306aef..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec2 extraSize;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump float blurRadius;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min( visualSize.x, visualSize.y );
-  vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy );
-  vCornerRadius = min( vCornerRadius, minSize * 0.5 );
-  vRectSize = visualSize / 2.0;
-  // optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0 - blurRadius;
-
-  vPosition = aPosition * (visualSize + 2.0 * blurRadius);
-  return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 811dc1d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-
-void main()
-{
-  OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  if(dist > 1.0)
-  {
-    OUT_COLOR.a = 0.0;
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    OUT_COLOR.a *= 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-}
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.vert
deleted file mode 100644 (file)
index 0a6a257..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec2 extraSize;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min( visualSize.x, visualSize.y );
-  vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min( vCornerRadius, minSize * 0.5 );
-  vRectSize = visualSize / 2.0;
-  // optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vPosition = aPosition* visualSize;
-  return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
index fef045b..bf93629 100644 (file)
@@ -1,7 +1,265 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef IS_REQUIRED_BLUR
+#define IS_REQUIRED_BLUR 0
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+#if IS_REQUIRED_BLUR
+uniform mediump float blurRadius;
+#endif
+
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+  gRadius =
+  mix(
+    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+    sign(vPosition.y) * 0.5 + 0.5
+  );
+#endif
+}
+
+void calculatePosition()
+{
+  gFragmentPosition = abs(vPosition) - vRectSize;
+  gCenterPosition = -gRadius;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+  gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+  gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+  gPotentialRange = 1.0;
+
+  gMaxOutlinePotential = gRadius + gPotentialRange;
+  gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+  gMaxInlinePotential = gMaxOutlinePotential;
+  gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+  // reduce defect near edge of rounded corner.
+  gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+  gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+  calculateCornerRadius();
+  calculatePosition();
+  calculatePotential();
+
+  setupMinMaxPotential();
+}
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+  mediump float potential = gPotential;
+
+  // default opacity of borderline is 0.0
+  mediump float borderlineOpacity = 0.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMinInlinePotential)
+  {
+    // potential is inside borderline range.
+    borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+  }
+
+  //calculate inside of borderline when outilneColor.a < 1.0
+  if(borderlineColor.a < 1.0)
+  {
+    mediump float tCornerRadius = -gCenterPosition;
+    mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+    mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+    if(potential > MaxTexturelinePotential)
+    {
+      // potential is out of texture range. use borderline color instead of texture
+      textureColor = vec4(borderlineColor.xyz, 0.0);
+    }
+    else if(potential > MinTexturelinePotential)
+    {
+      // potential is in texture range
+      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+    }
+    borderlineOpacity *= borderlineColor.a;
+  }
+  return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+  mediump float potential = gPotential;
+
+  // default opacity is 1.0
+  mediump float opacity = 1.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMaxOutlinePotential)
+  {
+    // potential is out of borderline range
+    opacity = 0.0;
+  }
+  else if(potential > gMinOutlinePotential)
+  {
+    opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+  }
+  return opacity;
+}
+#endif
+
+#if IS_REQUIRED_BLUR
+mediump float calculateBlurOpacity()
+{
+// Don't use borderline!
+  mediump vec2 v = gDiff;
+  mediump float cy = gRadius + blurRadius;
+  mediump float cr = gRadius + blurRadius;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+  // This routine make perfect circle. If corner radius is not exist, we don't consider prefect circle.
+  cy = min(cy, min(vRectSize.x, vRectSize.y) - gRadius);
+#endif
+  v = vec2(min(v.x, v.y), max(v.x, v.y));
+  v = v + cy;
+
+  mediump float potential = 0.0;
+  mediump float alias = min(gRadius, 1.0);
+  mediump float potentialMin = cy + gRadius - blurRadius - alias;
+  mediump float potentialMax = cy + gRadius + blurRadius + alias;
+
+  // move center of circles for reduce defact
+  mediump float cyDiff = min(cy, 0.2 * blurRadius);
+  cy -= cyDiff;
+  cr += cyDiff;
+
+  mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
+
+  if(diffFromBaseline > 0.0)
+  {
+    // out of calculation bound.
+    potential = v.y;
+
+    // for anti-alias when blurRaidus = 0.0
+    mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
+    mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
+    potentialMin += potentialDiff;
+    potentialMax -= potentialDiff;
+  }
+  else
+  {
+    // get some circle centered (x, x) and radius (r = cr / cy * x)
+    // s.t. point v is on that circle
+    // highest point of that circle is (x, x + r) and potential is x + r
+
+    // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
+#if IS_REQUIRED_ROUNDED_CORNER
+    // NOTE : lowspec HW cannot calculate here. need to reduce numeric error
+    mediump float A = (cr * cr - 2.0 * cy * cy);
+    mediump float B = cy * (v.x + v.y);
+    mediump float V = dot(v,v);
+    mediump float D = B * B + A * V;
+    potential = V * (cr + cy) / (sqrt(D) + B);
+#else
+    // We can simplify this value cause cy = 0.8 * blurRadius, cr = 1.2 * blurRadius
+    // potential = 5.0*(sqrt(4.0*(v.x+v.y)^2 + dot(v,v)) - 2.0*(v.x+v.y));
+    //           = 10.0*(v.x+v.y) * (sqrt(1.0 + (length(v) / (2.0*(v.x+v.y)))^2) - 1.0);
+    //           = 10.0*(v.x+v.y) * (sqrt(1.25 - x + x^2) - 1.0);
+    //          ~= 10.0*(v.x+v.y) * (0.11803399 - 0.44721360x + 0.35777088x^2 - 0.14310x^3 + O(x^4)) (Taylor series)
+    //          ~= -1.0557281 * (v.x + v.y) + 2.236068 * length(v) - ~~~ (here, x <= 0.5 * (1.0 - sqrt(0.5)) < 0.1464467)
+    // Note : This simplify need cause we should use it on lowspec HW.
+    mediump float x = 0.5 * (1.0 - length(v) / (v.x + v.y));
+    potential = -1.0557281 * (v.x + v.y) + 2.236068 * length(v) + 10.0 * (v.x + v.y) * (0.35777088 - 0.14310 * x) * x * x;
+#endif
+  }
+
+  return 1.0 - smoothstep(potentialMin, potentialMax, potential);
+}
+#endif
 
 void main()
 {
-  OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-}
\ No newline at end of file
+  lowp vec4 targetColor = vec4(mixColor, 1.0) * uColor;
+
+#if IS_REQUIRED_BLUR || IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  // skip most potential calculate for performance
+  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+  {
+    OUT_COLOR = targetColor;
+    return;
+  }
+  PreprocessPotential();
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  targetColor = convertBorderlineColor(targetColor);
+#endif
+  OUT_COLOR = targetColor;
+
+#if IS_REQUIRED_BLUR
+  mediump float opacity = calculateBlurOpacity();
+  OUT_COLOR.a *= opacity;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  mediump float opacity = calculateCornerOpacity();
+  OUT_COLOR.a *= opacity;
+#endif
+}
index 993d9d4..2798185 100644 (file)
@@ -1,4 +1,22 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef IS_REQUIRED_BLUR
+#define IS_REQUIRED_BLUR 0
+#endif
+
 INPUT mediump vec2 aPosition;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
 
 uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
@@ -9,16 +27,57 @@ uniform highp vec2 size;
 uniform mediump vec4 offsetSizeMode;
 uniform mediump vec2 origin;
 uniform mediump vec2 anchorPoint;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_BLUR
+uniform mediump float blurRadius;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
 uniform mediump vec2 extraSize;
 
 vec4 ComputeVertexPosition()
 {
   vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+  vRectSize = visualSize * 0.5;
+  vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+  mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+  vCornerRadius = min(vCornerRadius, minSize * 0.5);
+  // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BLUR
+  vPosition = aPosition * (visualSize + 2.0 * blurRadius);
+  vOptRectSize -= blurRadius + 1.0;
+#elif IS_REQUIRED_BORDERLINE
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0))* borderlineWidth);
+  vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  vPosition = aPosition * visualSize;
+#else
+  mediump vec2 vPosition = aPosition * visualSize;
+#endif
+  return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
 }
 
 void main()
 {
   gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
\ No newline at end of file
+}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-rounded-corner-shader.vert
deleted file mode 100644 (file)
index bd08a63..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw);
-  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min(visualSize.x, visualSize.y);
-  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min(vCornerRadius, minSize * 0.5);
-  vRectSize = visualSize * 0.5;
-  // Optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vPosition = aPosition * visualSize;
-  return vec4((aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-shader.vert
deleted file mode 100644 (file)
index 018e260..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 1b29ae0..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  if(dist > 1.0)
-  {
-    gl_FragColor = vec4(0.0);
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    gl_FragColor *= 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-shader.frag
deleted file mode 100644 (file)
index 1ec04b2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 68df0c5..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  if(dist > 1.0)
-  {
-    gl_FragColor = vec4(0.0);
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    gl_FragColor *= 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-shader.frag
deleted file mode 100644 (file)
index 8d37383..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag
new file mode 100644 (file)
index 0000000..305ff92
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef RADIAL
+#define RADIAL 0
+#endif
+
+INPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform sampler2D sTexture; // sampler1D?
+uniform lowp vec4 uColor;
+uniform lowp vec3 mixColor;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+  gRadius =
+  mix(
+    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+    sign(vPosition.y) * 0.5 + 0.5
+  );
+#endif
+}
+
+void calculatePosition()
+{
+  gFragmentPosition = abs(vPosition) - vRectSize;
+  gCenterPosition = -gRadius;
+#if IS_REQUIRED_BORDERLINE
+  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+  gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+  gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+  gPotentialRange = 1.0;
+
+  gMaxOutlinePotential = gRadius + gPotentialRange;
+  gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if IS_REQUIRED_BORDERLINE
+  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+  gMaxInlinePotential = gMaxOutlinePotential;
+  gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+  // reduce defect near edge of rounded corner.
+  gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+  gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+  calculateCornerRadius();
+  calculatePosition();
+  calculatePotential();
+
+  setupMinMaxPotential();
+}
+#endif
+
+
+#if IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+  mediump float potential = gPotential;
+
+  // default opacity of borderline is 0.0
+  mediump float borderlineOpacity = 0.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMinInlinePotential)
+  {
+    // potential is inside borderline range.
+    borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+  }
+
+  //calculate inside of borderline when outilneColor.a < 1.0
+  if(borderlineColor.a < 1.0)
+  {
+    mediump float tCornerRadius = -gCenterPosition;
+    mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+    mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+    if(potential > MaxTexturelinePotential)
+    {
+      // potential is out of texture range. use borderline color instead of texture
+      textureColor = vec4(borderlineColor.xyz, 0.0);
+    }
+    else if(potential > MinTexturelinePotential)
+    {
+      // potential is in texture range
+      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+    }
+    borderlineOpacity *= borderlineColor.a;
+  }
+  return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+  mediump float potential = gPotential;
+
+  // default opacity is 1.0
+  mediump float opacity = 1.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMaxOutlinePotential)
+  {
+    // potential is out of borderline range
+    opacity = 0.0;
+  }
+  else if(potential > gMinOutlinePotential)
+  {
+    opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+  }
+  return opacity;
+}
+#endif
+
+void main()
+{
+#if RADIAL
+  lowp vec4 textureColor = TEXTURE(sTexture, vec2(length(vTexCoord), 0.5)) * vec4(mixColor, 1.0) * uColor;
+#else
+  lowp vec4 textureColor = TEXTURE(sTexture, vec2(vTexCoord.y, 0.5)) * vec4(mixColor, 1.0) * uColor;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  // skip most potential calculate for performance
+  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+  {
+    OUT_COLOR = textureColor;
+    return;
+  }
+  PreprocessPotential();
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  textureColor = convertBorderlineColor(textureColor);
+#endif
+  OUT_COLOR = textureColor;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+  mediump float opacity = calculateCornerOpacity();
+  OUT_COLOR *= opacity;
+#endif
+}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert
new file mode 100644 (file)
index 0000000..f9e80fe
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef USER_SPACE
+#define USER_SPACE 0
+#endif
+
+INPUT mediump vec2 aPosition;
+OUTPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
+uniform mediump mat3 uAlignmentMatrix;
+
+//Visual size and offset
+uniform mediump vec2 offset;
+uniform highp vec2 size;
+uniform mediump vec4 offsetSizeMode;
+uniform mediump vec2 origin;
+uniform mediump vec2 anchorPoint;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
+
+vec4 ComputeVertexPosition()
+{
+  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
+  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  vRectSize = visualSize * 0.5;
+  vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if IS_REQUIRED_BORDERLINE
+  mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+  mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+  vCornerRadius = min(vCornerRadius, minSize * 0.5);
+  // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+  vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  vPosition = aPosition * visualSize;
+#else
+  mediump vec2 vPosition = aPosition * visualSize;
+#endif
+
+  return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
+}
+
+void main()
+{
+  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
+  gl_Position = uMvpMatrix * ComputeVertexPosition();
+#if USER_SPACE
+  vertexPosition.xyz *= uSize;
+#endif
+  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
+}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-rounded-corner-shader.vert
deleted file mode 100644 (file)
index 23ded26..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw);
-  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min(visualSize.x, visualSize.y);
-  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min(vCornerRadius, minSize * 0.5);
-  vRectSize = visualSize * 0.5;
-  // Optimze fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vCornerRadius = max(vCornerRadius, 1.0);
-  vPosition = aPosition * visualSize;
-  return vec4((aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vertexPosition.xyz *= uSize;
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-shader.vert
deleted file mode 100644 (file)
index ca1eab6..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vertexPosition.xyz *= uSize;
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-atlas-clamp-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-atlas-clamp-shader.frag
deleted file mode 100644 (file)
index 0d87f9d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform mediump vec4 uAtlasRect;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
-  mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
-  OUT_COLOR = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
-}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-atlas-various-wrap-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-atlas-various-wrap-shader.frag
deleted file mode 100644 (file)
index eeb8a0c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform mediump vec4 uAtlasRect;
-
-// WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
-uniform lowp vec2 wrapMode;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
-
-{
-  mediump float coord;
-  if( wrap > 1.5 )\n // REFLECT
-    coord = 1.0-abs(fract(coordinate*0.5)*2.0 - 1.0);
-  else \n// warp == 0 or 1
-    coord = mix(coordinate, fract( coordinate ), wrap);
-  return clamp( mix(range.x, range.y, coord), range.x, range.y );
-}
-
-void main()
-{
-  mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
-                                wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
-  OUT_COLOR = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
-}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-no-atlas-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-no-atlas-shader.frag
deleted file mode 100644 (file)
index ffc960c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
-  OUT_COLOR = TEXTURE( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 6eacb93..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    OUT_COLOR = TEXTURE(sTexture, vTexCoord) * uColor * vec4(mixColor, 1.0);
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  mediump float opacity = 1.0;
-  if(dist > 1.0)
-  {
-    opacity = 0.0;
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    opacity = 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-
-  OUT_COLOR = TEXTURE(sTexture, vTexCoord) * uColor * vec4(mixColor, 1.0);
-  OUT_COLOR.a *= opacity;
-  OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.vert
deleted file mode 100644 (file)
index c35b1b6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vTexCoord;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump vec4 pixelArea;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-uniform mediump vec2 extraSize;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw) + extraSize;
-  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min(visualSize.x, visualSize.y);
-  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min(vCornerRadius, minSize * 0.5);
-  vRectSize = visualSize * 0.5;
-  // Optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vPosition = aPosition* visualSize;
-  return vec4(vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-  vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5));
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
new file mode 100644 (file)
index 0000000..e83d463
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef ATLAS_DEFAULT_WARP
+#define ATLAS_DEFAULT_WARP 0
+#endif
+#ifndef ATLAS_CUSTOM_WARP
+#define ATLAS_CUSTOM_WARP 0
+#endif
+
+INPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform sampler2D sTexture;
+#if ATLAS_DEFAULT_WARP
+uniform mediump vec4 uAtlasRect;
+#elif ATLAS_CUSTOM_WARP
+// WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
+uniform lowp vec2 wrapMode;
+#endif
+
+uniform lowp vec4 uColor;
+uniform lowp vec3 mixColor;
+uniform lowp float preMultipliedAlpha;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+
+#if ATLAS_CUSTOM_WARP
+mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
+{
+  mediump float coord;
+  if( wrap > 1.5 ) /* REFLECT */
+    coord = 1.0 - abs(fract(coordinate*0.5)*2.0 - 1.0);
+  else /* warp is 0 or 1 */
+    coord = mix(coordinate, fract(coordinate), wrap);
+  return clamp(mix(range.x, range.y, coord), range.x, range.y);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+  gRadius =
+  mix(
+    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+    sign(vPosition.y) * 0.5 + 0.5
+  );
+#endif
+}
+
+void calculatePosition()
+{
+  gFragmentPosition = abs(vPosition) - vRectSize;
+  gCenterPosition = -gRadius;
+#if IS_REQUIRED_BORDERLINE
+  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+  gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+  gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+  gPotentialRange = 1.0;
+
+  gMaxOutlinePotential = gRadius + gPotentialRange;
+  gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if IS_REQUIRED_BORDERLINE
+  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+  gMaxInlinePotential = gMaxOutlinePotential;
+  gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+  // reduce defect near edge of rounded corner.
+  gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+  gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+  calculateCornerRadius();
+  calculatePosition();
+  calculatePotential();
+
+  setupMinMaxPotential();
+}
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+  mediump float potential = gPotential;
+
+  // default opacity of borderline is 0.0
+  mediump float borderlineOpacity = 0.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMinInlinePotential)
+  {
+    // potential is inside borderline range.
+    borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+  }
+
+  //calculate inside of borderline when outilneColor.a < 1.0
+  if(borderlineColor.a < 1.0)
+  {
+    mediump float tCornerRadius = -gCenterPosition;
+    mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+    mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+    if(potential > MaxTexturelinePotential)
+    {
+      // potential is out of texture range. use borderline color instead of texture
+      textureColor = vec4(borderlineColor.xyz, 0.0);
+    }
+    else if(potential > MinTexturelinePotential)
+    {
+      // potential is in texture range
+      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+    }
+    borderlineOpacity *= borderlineColor.a;
+  }
+  return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+  mediump float potential = gPotential;
+
+  // default opacity is 1.0
+  mediump float opacity = 1.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMaxOutlinePotential)
+  {
+    // potential is out of borderline range
+    opacity = 0.0;
+  }
+  else if(potential > gMinOutlinePotential)
+  {
+    opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+  }
+  return opacity;
+}
+#endif
+
+void main()
+{
+#if ATLAS_DEFAULT_WARP
+  mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
+#elif ATLAS_CUSTOM_WARP
+  mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
+                                wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
+#else
+  mediump vec2 texCoord = vTexCoord;
+#endif
+
+  lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  // skip most potential calculate for performance
+  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+  {
+    OUT_COLOR = textureColor;
+    return;
+  }
+  PreprocessPotential();
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  textureColor = convertBorderlineColor(textureColor);
+#endif
+  OUT_COLOR = textureColor;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+  mediump float opacity = calculateCornerOpacity();
+  OUT_COLOR.a *= opacity;
+  OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
+#endif
+}
index fe0c35c..21d4084 100644 (file)
@@ -1,5 +1,20 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+
 INPUT mediump vec2 aPosition;
 OUTPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
 
 uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
@@ -11,17 +26,53 @@ uniform highp vec2 size;
 uniform mediump vec4 offsetSizeMode;
 uniform mediump vec2 origin;
 uniform mediump vec2 anchorPoint;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
 uniform mediump vec2 extraSize;
 
 vec4 ComputeVertexPosition()
 {
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+  vec2 visualSize = mix(uSize.xy * size, size, offsetSizeMode.zw) + extraSize;
+  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  vRectSize = visualSize * 0.5;
+  vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if IS_REQUIRED_BORDERLINE
+  mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+  mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+  vCornerRadius = min(vCornerRadius, minSize * 0.5);
+  // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+  vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  vPosition = aPosition * visualSize;
+#else
+  mediump vec2 vPosition = aPosition * visualSize;
+#endif
+
+  vTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5));
+  return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
 }
 
 void main()
 {
   gl_Position = uMvpMatrix * ComputeVertexPosition();
-  vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );
-}
\ No newline at end of file
+}
index 78e7331..134a327 100644 (file)
@@ -291,7 +291,10 @@ float Controller::Relayouter::GetHeightForWidth(Controller& controller, float wi
     // The implementation of Get LineCount property depends on calling GetHeightForWidth then read mLines.Count() from visualModel direct.
     // If the LineCount property is requested before rendering and layouting then the value will be zero, which is incorrect.
     // So we will not restore the previously backed-up mLines and mGlyphPositions from visualModel in such case.
-    bool restoreLinesAndGlyphPositions = visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0;
+    // Another case to skip restore is when the requested width equals the Control's width which means the caller need to update the old values.
+    // For example, when the text is changed.
+    bool restoreLinesAndGlyphPositions = (visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0)
+                                          && (visualModel->mControlSize.width != width);
 
     layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask, restoreLinesAndGlyphPositions);
 
diff --git a/dali-toolkit/internal/transition/transition-base-impl.cpp b/dali-toolkit/internal/transition/transition-base-impl.cpp
new file mode 100644 (file)
index 0000000..42fb10d
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2021 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-toolkit/internal/transition/transition-base-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/animation/key-frames.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/type-registry.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION(Dali::AlphaFunction::DEFAULT);
+
+Property::Map GetOriginalProperties(Dali::Toolkit::Control control)
+{
+  Property::Map propertyMap;
+  propertyMap.Insert(Dali::Actor::Property::ANCHOR_POINT, control[Dali::Actor::Property::ANCHOR_POINT]);
+  propertyMap.Insert(Dali::Actor::Property::PARENT_ORIGIN, control[Dali::Actor::Property::PARENT_ORIGIN]);
+  propertyMap.Insert(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT, control[Dali::Actor::Property::POSITION_USES_ANCHOR_POINT]);
+  propertyMap.Insert(Dali::Actor::Property::INHERIT_POSITION, control[Dali::Actor::Property::INHERIT_POSITION]);
+  propertyMap.Insert(Dali::Actor::Property::INHERIT_ORIENTATION, control[Dali::Actor::Property::INHERIT_ORIENTATION]);
+  propertyMap.Insert(Dali::Actor::Property::INHERIT_SCALE, control[Dali::Actor::Property::INHERIT_SCALE]);
+  propertyMap.Insert(Dali::Actor::Property::COLOR_MODE, control[Dali::Actor::Property::COLOR_MODE]);
+  propertyMap.Insert(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, control[Dali::Actor::Property::HEIGHT_RESIZE_POLICY]);
+  propertyMap.Insert(Dali::Actor::Property::WIDTH_RESIZE_POLICY, control[Dali::Actor::Property::WIDTH_RESIZE_POLICY]);
+  propertyMap.Insert(Dali::Actor::Property::POSITION, control[Dali::Actor::Property::POSITION]);
+  propertyMap.Insert(Dali::Actor::Property::ORIENTATION, control[Dali::Actor::Property::ORIENTATION]);
+  propertyMap.Insert(Dali::Actor::Property::SCALE, control[Dali::Actor::Property::SCALE]);
+  propertyMap.Insert(Dali::Actor::Property::COLOR, control[Dali::Actor::Property::COLOR]);
+
+  return propertyMap;
+}
+
+/**
+ * @brief Computes and center position by using transform properties.
+ * @param[in] anchorPoint anchorPoint of an actor.
+ * @param[in] positionUsesAnchorPoint positionUsesAnchorPoint of an actor.
+ * @param[in] size size of an actor.
+ * @param[in] scale scale of an actor.
+ * @param[in] orientation orientation of an actor.
+ */
+Vector3 CalculateCenterPosition(
+  const Vector3&    anchorPoint,
+  const bool        positionUsesAnchorPoint,
+  const Vector3&    size,
+  const Vector3&    scale,
+  const Quaternion& orientation)
+{
+  Vector3       centerPosition;
+  const Vector3 half(0.5f, 0.5f, 0.5f);
+  const Vector3 topLeft(0.0f, 0.0f, 0.5f);
+  // Calculate the center-point by applying the scale and rotation on the anchor point.
+  centerPosition = (half - anchorPoint) * size * scale;
+  centerPosition *= orientation;
+
+  // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
+  if(!positionUsesAnchorPoint)
+  {
+    centerPosition -= (topLeft - anchorPoint) * size;
+  }
+  return centerPosition;
+}
+
+} // anonymous namespace
+
+TransitionBasePtr TransitionBase::New()
+{
+  TransitionBasePtr transition = new TransitionBase();
+
+  // Second-phase construction
+  transition->Initialize();
+
+  return transition;
+}
+
+TransitionBase::TransitionBase()
+: mAlphaFunction(DEFAULT_ALPHA_FUNCTION),
+  mTimePeriod(TimePeriod(0.0f)),
+  mTransitionWithChild(false),
+  mMoveTargetChildren(false)
+{
+}
+
+void TransitionBase::Initialize()
+{
+  RegisterObject();
+}
+
+void TransitionBase::SetTimePeriod(const Dali::TimePeriod& timePeriod)
+{
+  if(timePeriod.durationSeconds < 0.0f)
+  {
+    DALI_LOG_WARNING("Duration should be greater than 0.0f.\n");
+  }
+  else
+  {
+    mTimePeriod.durationSeconds = timePeriod.durationSeconds;
+  }
+
+  if(timePeriod.delaySeconds < 0.0f)
+  {
+    DALI_LOG_WARNING("Delay should be greater than 0.0f.\n");
+    return;
+  }
+  else
+  {
+    mTimePeriod.delaySeconds = timePeriod.delaySeconds;
+  }
+}
+
+Dali::TimePeriod TransitionBase::GetTimePeriod() const
+{
+  return mTimePeriod;
+}
+
+void TransitionBase::TransitionWithChild(bool transitionWithChild)
+{
+  mTransitionWithChild = transitionWithChild;
+}
+
+void TransitionBase::PreProcess(Dali::Animation animation)
+{
+  mAnimation           = animation;
+  // Retrieve original property map of mTarget to backup and to reset after transition is finished.
+  mOriginalPropertyMap = GetOriginalProperties(mTarget);
+  mMoveTargetChildren  = false;
+  if(!mTransitionWithChild && mTarget.GetChildCount() > 0)
+  {
+    mMoveTargetChildren = true;
+    CopyTarget();
+  }
+  GetImplementation(mTarget).SetTransparent(false);
+}
+
+void TransitionBase::Play()
+{
+  if(!mTarget[Dali::Actor::Property::CONNECTED_TO_SCENE])
+  {
+    DALI_LOG_ERROR("The target is not added on the window\n");
+    return;
+  }
+
+  OnPlay();
+
+  SetAnimation();
+}
+
+void TransitionBase::SetAnimation()
+{
+  if(!mAnimation)
+  {
+    DALI_LOG_ERROR("animation is not initialized\n");
+    return;
+  }
+
+  for(uint32_t i = 0; i < mStartPropertyMap.Count(); ++i)
+  {
+    Property::Value* initialValuePointer = mInitialPropertyMap.Find(mStartPropertyMap.GetKeyAt(i).indexKey);
+    Property::Value* finishValue = mFinishPropertyMap.Find(mStartPropertyMap.GetKeyAt(i).indexKey);
+    if(finishValue)
+    {
+      Property::Value initialValue = mStartPropertyMap.GetValue(i);
+      if(initialValuePointer)
+      {
+        initialValue = *initialValuePointer;
+      }
+      AnimateBetween(mTarget, mStartPropertyMap.GetKeyAt(i).indexKey, initialValue, mStartPropertyMap.GetValue(i), *finishValue);
+    }
+  }
+}
+
+void TransitionBase::AnimateBetween(Dali::Toolkit::Control target, Property::Index index, Property::Value initialValue, Property::Value sourceValue, Property::Value destinationValue)
+{
+  if(mAnimation)
+  {
+    if(mTimePeriod.delaySeconds>0.0f)
+    {
+      Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
+      initialKeyframes.Add(0.0f, initialValue);
+      initialKeyframes.Add(1.0f, initialValue);
+      mAnimation.AnimateBetween(Property(target, index), initialKeyframes, TimePeriod(mTimePeriod.delaySeconds));
+    }
+    Dali::KeyFrames keyframes = Dali::KeyFrames::New();
+    keyframes.Add(0.0f, sourceValue);
+    keyframes.Add(1.0f, destinationValue);
+    mAnimation.AnimateBetween(Property(target, index), keyframes, mAlphaFunction, mTimePeriod);
+  }
+}
+
+void TransitionBase::CopyTarget()
+{
+  mCopiedActor = Dali::Actor::New();
+  mTarget.GetParent().Add(mCopiedActor);
+  mCopiedActor[Dali::DevelActor::Property::SIBLING_ORDER] = static_cast<int32_t>(mTarget[Dali::DevelActor::Property::SIBLING_ORDER]) + 1;
+  for(uint32_t i = 0; i < mTarget.GetChildCount(); ++i)
+  {
+    Dali::Actor child = mTarget.GetChildAt(i);
+    Dali::DevelActor::SwitchParent(child, mCopiedActor);
+  }
+
+  // Copy Size property to mCopiedActor because Size is not included mOriginalPropertyMap.
+  mCopiedActor[Dali::Actor::Property::SIZE] = mTarget.GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+  mCopiedActor.SetProperties(mOriginalPropertyMap);
+}
+
+void TransitionBase::TransitionFinished()
+{
+  OnFinished();
+
+  mTarget.SetProperties(mOriginalPropertyMap);
+  if(mMoveTargetChildren)
+  {
+    for(uint32_t i = 0; i < mCopiedActor.GetChildCount(); ++i)
+    {
+      Dali::Actor child = mCopiedActor.GetChildAt(i);
+      Dali::DevelActor::SwitchParent(child, mTarget);
+    }
+    mCopiedActor.Unparent();
+    mCopiedActor.Reset();
+  }
+  mAnimation.Reset();
+}
+
+Matrix TransitionBase::GetWorldTransform(Dali::Actor actor)
+{
+  enum InheritanceMode
+  {
+    DONT_INHERIT_TRANSFORM = 0,
+    INHERIT_POSITION       = 1,
+    INHERIT_SCALE          = 2,
+    INHERIT_ORIENTATION    = 4,
+    INHERIT_ALL            = INHERIT_POSITION | INHERIT_SCALE | INHERIT_ORIENTATION,
+  };
+
+  std::vector<Dali::Actor>     descentList;
+  std::vector<InheritanceMode> inheritanceModeList;
+  Dali::Actor                  currentActor = actor;
+  int                          inheritance  = 0;
+  do
+  {
+    inheritance = (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_ORIENTATION)) << 2) +
+                  (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_SCALE)) << 1) +
+                  static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_POSITION));
+    inheritanceModeList.push_back(static_cast<InheritanceMode>(inheritance));
+    descentList.push_back(currentActor);
+    currentActor = currentActor.GetParent();
+  } while(inheritance != DONT_INHERIT_TRANSFORM && currentActor);
+
+  Matrix  worldMatrix;
+  Vector3 localPosition;
+  for(unsigned int i(descentList.size() - 1); i < descentList.size(); --i)
+  {
+    Vector3    anchorPoint             = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::ANCHOR_POINT);
+    Vector3    parentOrigin            = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::PARENT_ORIGIN);
+    bool       positionUsesAnchorPoint = descentList[i].GetProperty<bool>(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT);
+    Vector3    size                    = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+    Vector3    actorPosition           = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::POSITION);
+    Quaternion localOrientation        = descentList[i].GetProperty<Quaternion>(Dali::Actor::Property::ORIENTATION);
+    Vector3    localScale              = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SCALE);
+
+    Vector3 centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
+    if(inheritanceModeList[i] != DONT_INHERIT_TRANSFORM && descentList[i].GetParent())
+    {
+      Matrix  localMatrix;
+      Vector3 parentSize = descentList[i + 1].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+      if(inheritanceModeList[i] == INHERIT_ALL)
+      {
+        localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
+        localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
+
+        //Update the world matrix
+        Matrix tempMatrix;
+        Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
+        worldMatrix = tempMatrix;
+      }
+      else
+      {
+        Vector3    parentPosition, parentScale;
+        Quaternion parentOrientation;
+        worldMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
+
+        if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
+        {
+          //Don't inherit scale
+          localScale /= parentScale;
+        }
+
+        if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
+        {
+          //Don't inherit orientation
+          parentOrientation.Invert();
+          localOrientation = parentOrientation * localOrientation;
+        }
+
+        if((inheritanceModeList[i] & INHERIT_POSITION) == 0)
+        {
+          localMatrix.SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
+          Matrix tempMatrix;
+          Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
+          worldMatrix = tempMatrix;
+          worldMatrix.SetTranslation(actorPosition + centerPosition);
+        }
+        else
+        {
+          localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
+          localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
+          Matrix tempMatrix;
+          Matrix::Multiply(tempMatrix, localMatrix, worldMatrix);
+          worldMatrix = tempMatrix;
+        }
+      }
+    }
+    else
+    {
+      localPosition = actorPosition + centerPosition;
+      worldMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
+    }
+  }
+
+  return worldMatrix;
+}
+
+Vector4 TransitionBase::GetWorldColor(Dali::Actor actor)
+{
+  std::vector<Dali::Actor>     descentList;
+  std::vector<Dali::ColorMode> inheritanceModeList;
+  Dali::Actor                  currentActor = actor;
+  Dali::ColorMode              inheritance  = Dali::ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA;
+  do
+  {
+    inheritance = currentActor.GetProperty<Dali::ColorMode>(Dali::Actor::Property::COLOR_MODE);
+    inheritanceModeList.push_back(inheritance);
+    descentList.push_back(currentActor);
+    currentActor = currentActor.GetParent();
+  } while(inheritance != Dali::ColorMode::USE_OWN_COLOR && currentActor);
+
+  Vector4 worldColor;
+  for(unsigned int i(descentList.size() - 1); i < descentList.size(); --i)
+  {
+    if(inheritanceModeList[i] == USE_OWN_COLOR || i == descentList.size() - 1)
+    {
+      worldColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
+    }
+    else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_ALPHA)
+    {
+      Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
+      worldColor       = Vector4(ownColor.r, ownColor.g, ownColor.b, ownColor.a * worldColor.a);
+    }
+    else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_COLOR)
+    {
+      Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
+      worldColor *= ownColor;
+    }
+  }
+
+  return worldColor;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition/transition-base-impl.h b/dali-toolkit/internal/transition/transition-base-impl.h
new file mode 100644 (file)
index 0000000..84ef316
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TRANSITION_BASE_H
+#define DALI_TOOLKIT_INTERNAL_TRANSITION_BASE_H
+
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/transition/transition-base.h>
+#include <dali-toolkit/public-api/transition/transition-set.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property-map.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+using TransitionBasePtr = IntrusivePtr<TransitionBase>;
+
+class TransitionBase : public BaseObject
+{
+public:
+  /**
+   * @brief Create a new TransitionBase object.
+   * @return A smart-pointer to the newly allocated TransitionBase.
+   */
+  static TransitionBasePtr New();
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionBase::SetTimePeriod()
+   */
+  void SetTimePeriod(const Dali::TimePeriod& timePeriod);
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionBase::GetTimePeriod()
+   */
+  Dali::TimePeriod GetTimePeriod() const;
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionBase::SetAlphaFunction()
+   */
+  void SetAlphaFunction(AlphaFunction alphaFunction)
+  {
+    mAlphaFunction = alphaFunction;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionBase::GetAlphaFunction()
+   */
+  AlphaFunction GetAlphaFunction() const
+  {
+    return mAlphaFunction;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionBase::TransitionWithChild()
+   */
+  void TransitionWithChild(bool transitionWithChild);
+
+  /**
+   * @brief Run processes those are required done before size/position negotiation.
+   * @param[in] animation animation for the transition
+   */
+  void PreProcess(Dali::Animation animation);
+
+  /**
+   * @brief Make property animation for Transition
+   */
+  void Play();
+
+  /**
+   * Emit the Finished signal
+   */
+  void TransitionFinished();
+
+protected:
+  /**
+   * @brief Set property map which will be used as a initial properties.
+   * @param[in] propertyMap propertyMap that will be used as a start value of transition.
+   */
+  void SetInitialPropertyMap(const Property::Map& propertyMap)
+  {
+    mInitialPropertyMap = propertyMap;
+  }
+  /**
+   * @brief Set property map which will be used as a animation start properties.
+   * @param[in] propertyMap propertyMap that will be used as a start value of transition.
+   */
+  void SetStartPropertyMap(const Property::Map& propertyMap)
+  {
+    mStartPropertyMap = propertyMap;
+  }
+
+  /**
+   * @brief Set property map which will be used as a animation finish properties.
+   * @param[in] propertyMap propertyMap that will be used as a finish value of transition.
+   */
+  void SetFinishPropertyMap(const Property::Map& propertyMap)
+  {
+    mFinishPropertyMap = propertyMap;
+  }
+
+  /**
+   * @brief Retrieve animation.
+   */
+  Dali::Animation GetAnimation()
+  {
+    return mAnimation;
+  }
+
+  /**
+   * @brief Set target which will be transition.
+   * @param[in] target control that will be transition.
+   */
+  void SetTarget(Dali::Toolkit::Control target)
+  {
+    mTarget = target;
+  }
+
+  /**
+   * @brief Gets world transform of input Actor.
+   * @param[in] actor actor for get world transform.
+   */
+  Matrix GetWorldTransform(Dali::Actor actor);
+
+  /**
+   * @brief Gets world color of input Actor.
+   * @param[in] actor actor for get world color.
+   */
+  Vector4 GetWorldColor(Dali::Actor actor);
+
+  /**
+   * @brief Returns whether this transition will be applied to children of target or not.
+   */
+  bool IsTransitionWithChild()
+  {
+    return mTransitionWithChild;
+  }
+
+protected:
+  /**
+   * Construct a new TransitionBase.
+   */
+  TransitionBase();
+
+  /**
+   * Second-phase constructor.
+   */
+  void Initialize();
+
+  /**
+   * Destructor
+   */
+  ~TransitionBase() = default;
+
+private:
+  // Undefined
+  TransitionBase(const TransitionBase&);
+
+  // Undefined
+  TransitionBase& operator=(const TransitionBase& rhs);
+
+private:
+  /**
+   * @brief Makes property animation for transition.
+   */
+  void SetAnimation();
+
+  /**
+   * @brief Adds a property on an animation between sourceValue and destimationValue.
+   * @param[in] target target control to be animated.
+   * @param[in] index property index for animation.
+   * @param[in] initialValue initial value of animation.
+   * @param[in] sourceValue source value of animation.
+   * @param[in] destinationValue destination value of animation.
+   */
+  void AnimateBetween(Dali::Toolkit::Control target, Property::Index index, Property::Value initialValue, Property::Value sourceValue, Property::Value destinationValue);
+
+  /**
+   * @brief Copy target to make clone for the child Actors
+   */
+  void CopyTarget();
+
+  /**
+   * @brief Make pair of Property::Map to be used for transition animation.
+   * Set the pair of Property::Map by using SetStartPropertyMap() and SetFinishPropertyMap(),
+   * then the properties of mTarget will be animated between them during transition duration.
+   * If the transition requires the information of world transform, let them be in this method.
+   * World transform and World color can be retrieved by using GetWorldTransform() and GetWorldColor() methods.
+   * And If it is needed to add additional custom animation than use GetAnimation() and add them.
+   *
+   * @note Do not set any properties in this methods.
+   */
+  virtual void OnPlay()
+  {
+  }
+
+  /**
+   * @brief If the transition is needed to do something after the transition is finished, let them be in this method.
+   */
+  virtual void OnFinished()
+  {
+  }
+
+private:
+  Dali::Toolkit::Control       mTarget;              ///< Target that will be animated.
+  Dali::Actor                  mCopiedActor;         ///< Copied View that will replace mTarget during transition
+  Dali::Animation              mAnimation;           ///< Property animations for the transition of mTarget
+  AlphaFunction                mAlphaFunction;       ///< Alpha function that will applied for the property animation
+  Property::Map                mInitialPropertyMap;  ///< Initial properties to be animated. (world transform)
+  Property::Map                mStartPropertyMap;    ///< Start properties to be animated. (world transform)
+  Property::Map                mFinishPropertyMap;   ///< Finish properties to be animated. (world transform)
+  Property::Map                mOriginalPropertyMap; ///< Original properties of mTarget to be used to restore after the transition is finished.
+  Dali::TimePeriod             mTimePeriod;          ///< TimePeriod of transition
+  bool                         mTransitionWithChild; ///< True, if mTarget transition is inherit to its child Actors.
+                                                     ///< If this is false, the child Actors are moved to the child of mCopiedActor that will have original properties of target Actor during Transition.
+  bool mMoveTargetChildren;                          ///< Flag, if mTransitionWithChild is false and mTarget has children than True.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::TransitionBase& GetImplementation(Dali::Toolkit::TransitionBase& animation)
+{
+  DALI_ASSERT_ALWAYS(animation && "TransitionBase handle is empty");
+
+  BaseObject& handle = animation.GetBaseObject();
+
+  return static_cast<Internal::TransitionBase&>(handle);
+}
+
+inline const Internal::TransitionBase& GetImplementation(const Dali::Toolkit::TransitionBase& animation)
+{
+  DALI_ASSERT_ALWAYS(animation && "TransitionBase handle is empty");
+
+  const BaseObject& handle = animation.GetBaseObject();
+
+  return static_cast<const Internal::TransitionBase&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TRANSITION_BASE_H
diff --git a/dali-toolkit/internal/transition/transition-impl.cpp b/dali-toolkit/internal/transition/transition-impl.cpp
new file mode 100644 (file)
index 0000000..ef193f6
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2021 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-toolkit/internal/transition/transition-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION(Dali::AlphaFunction::DEFAULT);
+
+} // anonymous namespace
+
+TransitionPtr Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod)
+{
+  float delaySeconds = timePeriod.delaySeconds;
+  if(delaySeconds < 0.0f)
+  {
+    DALI_LOG_WARNING("delay should be greater than 0.0f.\n");
+    delaySeconds = 0.0f;
+  }
+
+  float durationSeconds = timePeriod.durationSeconds;
+  if(durationSeconds < 0.0f)
+  {
+    DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
+    durationSeconds = 0.0f;
+  }
+
+  TransitionPtr transition = new Transition(source, destination, TimePeriod(delaySeconds, durationSeconds));
+
+  // Second-phase construction
+  transition->Initialize();
+
+  return transition;
+}
+
+Transition::Transition(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod)
+: TransitionBase(),
+  mSourceControl(source),
+  mDestinationControl(destination)
+{
+  SetTarget(destination);
+  SetTimePeriod(timePeriod);
+}
+
+Transition::~Transition()
+{
+}
+
+void Transition::OnPlay()
+{
+  if(!mSourceControl[Dali::Actor::Property::CONNECTED_TO_SCENE] ||
+     !mDestinationControl[Dali::Actor::Property::CONNECTED_TO_SCENE])
+  {
+    DALI_LOG_ERROR("The source or destination is not added on the window\n");
+    return;
+  }
+
+  //Make startPropertyMap and finishPropertyMap to use for property animation.
+  Matrix     sourceWorldTransform = mSourceControl[Dali::Actor::Property::WORLD_MATRIX];
+  Vector3    sourcePosition, sourceScale;
+  Quaternion sourceOrientation;
+  sourceWorldTransform.GetTransformComponents(sourcePosition, sourceOrientation, sourceScale);
+
+  Matrix     destinationWorldTransform = GetWorldTransform(mDestinationControl);
+  Vector3    destinationPosition, destinationScale;
+  Quaternion destinationOrientation;
+  destinationWorldTransform.GetTransformComponents(destinationPosition, destinationOrientation, destinationScale);
+
+  Vector3       targetSize  = mDestinationControl[Dali::Actor::Property::SIZE];
+  Vector4       targetColor = GetWorldColor(mDestinationControl);
+  Property::Map startPropertyMap;
+  Property::Map finishPropertyMap;
+
+  // Use world transform if this transition requires animation of transform.
+  mDestinationControl[Dali::Actor::Property::ANCHOR_POINT]               = AnchorPoint::CENTER;
+  mDestinationControl[Dali::Actor::Property::PARENT_ORIGIN]              = ParentOrigin::CENTER;
+  mDestinationControl[Dali::Actor::Property::POSITION_USES_ANCHOR_POINT] = true;
+  mDestinationControl[Dali::Actor::Property::INHERIT_POSITION]           = false;
+  mDestinationControl[Dali::Actor::Property::INHERIT_ORIENTATION]        = false;
+  mDestinationControl[Dali::Actor::Property::INHERIT_SCALE]              = false;
+  mDestinationControl[Dali::Actor::Property::COLOR_MODE]                 = Dali::ColorMode::USE_OWN_COLOR;
+
+  // Set animation of Transform
+  startPropertyMap.Insert(Dali::Actor::Property::POSITION, sourcePosition);
+  finishPropertyMap.Insert(Dali::Actor::Property::POSITION, destinationPosition);
+
+  startPropertyMap.Insert(Dali::Actor::Property::ORIENTATION, sourceOrientation);
+  finishPropertyMap.Insert(Dali::Actor::Property::ORIENTATION, destinationOrientation);
+
+  startPropertyMap.Insert(Dali::Actor::Property::SCALE, sourceScale);
+  finishPropertyMap.Insert(Dali::Actor::Property::SCALE, destinationScale);
+
+  Vector4 sourceColor = mSourceControl.GetCurrentProperty<Vector4>(Dali::Actor::Property::WORLD_COLOR);
+  startPropertyMap.Insert(Dali::Actor::Property::COLOR, sourceColor);
+  finishPropertyMap.Insert(Dali::Actor::Property::COLOR, targetColor);
+
+  // Set animation for other properties if source and destination is different.
+  Vector3 sourceSize = mSourceControl.GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE);
+  if(sourceSize != targetSize)
+  {
+    startPropertyMap.Insert(Dali::Actor::Property::SIZE, sourceSize);
+    finishPropertyMap.Insert(Dali::Actor::Property::SIZE, targetSize);
+  }
+
+  SetStartPropertyMap(startPropertyMap);
+  SetFinishPropertyMap(finishPropertyMap);
+
+  // source View becomes transparent during transition.
+  if(IsTransitionWithChild())
+  {
+    mSourceControl[Dali::Actor::Property::VISIBLE] = false;
+  }
+  else
+  {
+    GetImplementation(mSourceControl).SetTransparent(true);
+  }
+
+  Dali::Animation animation = GetAnimation();
+  if(!animation)
+  {
+    DALI_LOG_ERROR("animation is still not initialized\n");
+    return;
+  }
+  Dali::Toolkit::DevelControl::CreateTransitions(mDestinationControl, animation, mSourceControl, GetAlphaFunction(), GetTimePeriod());
+}
+
+void Transition::OnFinished()
+{
+  if(IsTransitionWithChild())
+  {
+    mSourceControl[Dali::Actor::Property::VISIBLE] = true;
+  }
+  else
+  {
+    GetImplementation(mSourceControl).SetTransparent(false);
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition/transition-impl.h b/dali-toolkit/internal/transition/transition-impl.h
new file mode 100644 (file)
index 0000000..d9120bf
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TRANSITION_H
+#define DALI_TOOLKIT_INTERNAL_TRANSITION_H
+
+/*
+ * Copyright (c) 2021 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-toolkit/internal/transition/transition-base-impl.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/transition/transition.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+using TransitionPtr = IntrusivePtr<Transition>;
+
+class Transition : public TransitionBase
+{
+public:
+  /**
+   * @brief Create a new Transition object.
+   * @param[in] source A source control of this transition.
+   * @param[in] destination A destination control of this transition.
+   * @param[in] durationSeconds The duration of the animation.
+   * @return A smart-pointer to the newly allocated Transition.
+   */
+  static TransitionPtr New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod);
+
+protected:
+  /**
+   * @copydoc Dali::Toolkit::Transition::OnPlay()
+   */
+  void OnPlay() override;
+
+  /**
+   * @brief Emit the Finished signal
+   */
+  void OnFinished() override;
+
+protected:
+  /**
+   * @brief Construct a new Transition.
+   */
+  Transition(Dali::Toolkit::Control source,
+             Dali::Toolkit::Control destination,
+             TimePeriod             timePeriod);
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference()
+   */
+  ~Transition() override;
+
+private:
+  // Undefined
+  Transition(const Transition&);
+
+  // Undefined
+  Transition& operator=(const Transition& rhs);
+
+private:
+  Dali::Toolkit::Control mSourceControl;
+  Dali::Toolkit::Control mDestinationControl;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Transition& GetImplementation(Dali::Toolkit::Transition& transition)
+{
+  DALI_ASSERT_ALWAYS(transition && "Transition handle is empty");
+
+  BaseObject& handle = transition.GetBaseObject();
+
+  return static_cast<Internal::Transition&>(handle);
+}
+
+inline const Internal::Transition& GetImplementation(const Dali::Toolkit::Transition& transition)
+{
+  DALI_ASSERT_ALWAYS(transition && "Transition handle is empty");
+
+  const BaseObject& handle = transition.GetBaseObject();
+
+  return static_cast<const Internal::Transition&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TRANSITION_H
diff --git a/dali-toolkit/internal/transition/transition-lifecycle-controller.cpp b/dali-toolkit/internal/transition/transition-lifecycle-controller.cpp
new file mode 100644 (file)
index 0000000..1a8c238
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 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-toolkit/internal/transition/transition-lifecycle-controller.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition/transition-set-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+void TransitionLifecycleController::AddTransitions(Dali::Toolkit::TransitionSet transitions)
+{
+  mTransitionList.push_back(transitions);
+  transitions.FinishedSignal().Connect(this, &TransitionLifecycleController::RemoveTransitions);
+}
+
+void TransitionLifecycleController::RemoveTransitions(Dali::Toolkit::TransitionSet &transitions)
+{
+  mTransitionList.erase(std::remove(mTransitionList.begin(), mTransitionList.end(), transitions));
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition/transition-lifecycle-controller.h b/dali-toolkit/internal/transition/transition-lifecycle-controller.h
new file mode 100644 (file)
index 0000000..8511635
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TRANSITION_PLAYLIST_H
+#define DALI_TOOLKIT_INTERNAL_TRANSITION_PLAYLIST_H
+
+/*
+ * Copyright (c) 2021 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 <cstdio>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/transition/transition-set.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class TransitionLifecycleController;
+
+namespace
+{
+std::unique_ptr<TransitionLifecycleController> instance = nullptr;
+std::once_flag                                 onceFlag;
+} // namespace
+
+class TransitionLifecycleController : public ConnectionTracker
+{
+public:
+  static TransitionLifecycleController& GetInstance()
+  {
+    std::call_once(onceFlag, []() {
+      instance.reset(new TransitionLifecycleController);
+    });
+    return *(instance.get());
+  }
+
+  void AddTransitions(Dali::Toolkit::TransitionSet transitions);
+
+private:
+
+  void RemoveTransitions(Dali::Toolkit::TransitionSet &transitions);
+
+  /**
+   * Construct a new TransitionLifecycleController.
+   */
+  TransitionLifecycleController() = default;
+
+  // Undefined
+  TransitionLifecycleController(const TransitionLifecycleController&) = delete;
+
+  // Undefined
+  TransitionLifecycleController& operator=(const TransitionLifecycleController& rhs) = delete;
+
+private:
+  std::vector<Dali::Toolkit::TransitionSet> mTransitionList;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TRANSITION_PLAYLIST_H
+;
\ No newline at end of file
diff --git a/dali-toolkit/internal/transition/transition-set-impl.cpp b/dali-toolkit/internal/transition/transition-set-impl.cpp
new file mode 100644 (file)
index 0000000..ad7ca62
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2021 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-toolkit/internal/transition/transition-set-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition/transition-lifecycle-controller.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+// Signals
+static constexpr std::string_view SIGNAL_FINISHED = "finished";
+
+BaseHandle Create()
+{
+  return Dali::Toolkit::TransitionSet::New();
+}
+
+TypeRegistration mType(typeid(Dali::Toolkit::TransitionSet), typeid(Dali::BaseHandle), Create);
+
+SignalConnectorType signalConnector1(mType, std::string(SIGNAL_FINISHED), &TransitionSet::DoConnectSignal);
+
+} // anonymous namespace
+
+TransitionSetPtr TransitionSet::New()
+{
+  TransitionSetPtr transitionSet = new TransitionSet();
+
+  return transitionSet;
+}
+
+TransitionSet::TransitionSet()
+{
+}
+
+TransitionSet::~TransitionSet()
+{
+  mTransitions.clear();
+}
+
+void TransitionSet::AddTransition(TransitionBasePtr transition)
+{
+  mTransitions.push_back(transition);
+}
+
+TransitionBase* TransitionSet::GetTransitionAt(uint32_t index) const
+{
+  TransitionBase* result(nullptr);
+  if(index < GetTransitionCount())
+  {
+    result = mTransitions[index].Get();
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: Invalid index to TransitionSet::GetTransitionAt\n");
+  }
+
+  return result;
+}
+
+uint32_t TransitionSet::GetTransitionCount() const
+{
+  return mTransitions.size();
+}
+
+void TransitionSet::Play()
+{
+  Adaptor::Get().RegisterProcessor(*this, true);
+  Adaptor::Get().RegisterProcessor(*this, false);
+  TransitionLifecycleController::GetInstance().AddTransitions(Dali::Toolkit::TransitionSet(this));
+}
+
+void TransitionSet::TransitionPreProcess()
+{
+  float lastDuration = 0.0f;
+  for(auto&& transition : mTransitions)
+  {
+    TimePeriod timePeriod = transition->GetTimePeriod();
+    if(lastDuration <= timePeriod.durationSeconds + timePeriod.delaySeconds)
+    {
+      lastDuration = timePeriod.durationSeconds + timePeriod.delaySeconds;
+    }
+  }
+  mAnimation = Dali::Animation::New(lastDuration);
+
+  for(auto&& transition : mTransitions)
+  {
+    transition->PreProcess(mAnimation);
+  }
+}
+
+void TransitionSet::TransitionStart()
+{
+  for(auto&& transition : mTransitions)
+  {
+    transition->Play();
+  }
+
+  mAnimation.FinishedSignal().Connect(this, &TransitionSet::TransitionFinished);
+  mAnimation.Play();
+}
+
+void TransitionSet::TransitionFinished(Dali::Animation& source)
+{
+  for(auto&& transition : mTransitions)
+  {
+    transition->TransitionFinished();
+  }
+
+  EmitFinishedSignal();
+}
+
+Dali::Toolkit::TransitionSet::TransitionSetSignalType& TransitionSet::FinishedSignal()
+{
+  return mFinishedSignal;
+}
+
+void TransitionSet::EmitFinishedSignal()
+{
+  if(!mFinishedSignal.Empty())
+  {
+    Dali::Toolkit::TransitionSet handle(this);
+    mFinishedSignal.Emit(handle);
+  }
+}
+
+bool TransitionSet::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
+{
+  bool           connected(false);
+  TransitionSet* transitionSet = static_cast<TransitionSet*>(object); // TypeRegistry guarantees that this is the correct type.
+
+  if(SIGNAL_FINISHED == signalName)
+  {
+    transitionSet->FinishedSignal().Connect(tracker, functor);
+    connected = true;
+  }
+
+  return connected;
+}
+
+void TransitionSet::Process(bool postProcessor)
+{
+  if(!postProcessor)
+  {
+    TransitionPreProcess();
+  }
+  else
+  {
+    TransitionStart();
+  }
+  Adaptor::Get().UnregisterProcessor(*this, postProcessor);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition/transition-set-impl.h b/dali-toolkit/internal/transition/transition-set-impl.h
new file mode 100644 (file)
index 0000000..eb9962d
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TRANSITION_SET_H
+#define DALI_TOOLKIT_INTERNAL_TRANSITION_SET_H
+
+/*
+ * Copyright (c) 2021 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-toolkit/internal/transition/transition-impl.h>
+#include <dali-toolkit/public-api/transition/transition-set.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/processor-interface.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/connection-tracker.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+using TransitionSetPtr = IntrusivePtr<TransitionSet>;
+
+class TransitionSet : public BaseObject, public ConnectionTracker, public Integration::Processor
+{
+public:
+  /**
+   * Create a new TransitionSet object.
+   * @return A smart-pointer to the newly allocated TransitionSet.
+   */
+  static TransitionSetPtr New();
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionSet::AddTransition(TransitionPtr transition)
+   */
+  void AddTransition(TransitionBasePtr transition);
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionSet::GetTransitionAt(uint32_t index)
+   */
+  TransitionBase* GetTransitionAt(uint32_t index) const;
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionSet::GetTransitionCount()
+   */
+  uint32_t GetTransitionCount() const;
+
+  /**
+   * @brief Make ready this transition set to play.
+   * Transitions in this transition set will be create property animations at the end of this tick of main thread.
+   */
+  void Play();
+
+  /**
+   * @copydoc Dali::Toolkit::TransitionSet::FinishedSignal()
+   */
+  Dali::Toolkit::TransitionSet::TransitionSetSignalType& FinishedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor);
+
+private:
+  /**
+   * @brief Set pre process of each transition.
+   */
+  void TransitionPreProcess();
+
+  /**
+   * @brief Start to play each of Transition.
+   * This method called at the end of event thread tick, and this method call OnPlay method of TransitionBase internally.
+   */
+  void TransitionStart();
+
+  /**
+   * @brief Remove each finished TransitionBase from play list.
+   * If all transitions are finished emit Finished signal.
+   */
+  void TransitionFinished(Dali::Animation& source);
+
+  /**
+   * Emit the Finished signal
+   */
+  void EmitFinishedSignal();
+
+protected: // Implementation of Processor
+  /**
+   * @copydoc Dali::Integration::Processor::Process()
+   */
+  void Process(bool postProcessor) override;
+
+protected:
+  /**
+   * Construct a new TransitionSet.
+   */
+  TransitionSet();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  ~TransitionSet() override;
+
+private:
+  // Undefined
+  TransitionSet(const TransitionSet&);
+
+  // Undefined
+  TransitionSet& operator=(const TransitionSet& rhs);
+
+private:
+  Dali::Toolkit::TransitionSet::TransitionSetSignalType mFinishedSignal{};
+  std::vector<TransitionBasePtr>                        mTransitions;
+  Dali::Animation                                       mAnimation;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::TransitionSet& GetImplementation(Dali::Toolkit::TransitionSet& transitionSet)
+{
+  DALI_ASSERT_ALWAYS(transitionSet && "TransitionSet handle is empty");
+
+  BaseObject& handle = transitionSet.GetBaseObject();
+
+  return static_cast<Internal::TransitionSet&>(handle);
+}
+
+inline const Internal::TransitionSet& GetImplementation(const Dali::Toolkit::TransitionSet& transitionSet)
+{
+  DALI_ASSERT_ALWAYS(transitionSet && "TransitionSet handle is empty");
+
+  const BaseObject& handle = transitionSet.GetBaseObject();
+
+  return static_cast<const Internal::TransitionSet&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TRANSITION_SET_H
index c9623a6..58506fd 100644 (file)
@@ -538,8 +538,12 @@ void AnimatedImageVisual::OnSetTransform()
 void AnimatedImageVisual::OnInitialize()
 {
   bool   defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
-  bool   atlasing        = false;
-  Shader shader          = mImageVisualShaderFactory.GetShader(mFactoryCache, atlasing, defaultWrapMode, IsRoundedCornerRequired());
+  Shader shader          = mImageVisualShaderFactory.GetShader(
+    mFactoryCache,
+    TextureAtlas::DISABLED,
+    defaultWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
+    IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+    IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED);
 
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
 
index c6604ad..edd7b1b 100644 (file)
@@ -295,7 +295,13 @@ void AnimatedVectorImageVisual::OnInitialize(void)
   }
   else
   {
-    shader = mImageVisualShaderFactory.GetShader(mFactoryCache, false, true, IsRoundedCornerRequired());
+    shader = mImageVisualShaderFactory.GetShader(
+      mFactoryCache,
+      TextureAtlas::DISABLED,
+      DefaultTextureWrapMode::APPLY,
+      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+    );
   }
 
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
index cf6abd3..8f748cf 100644 (file)
@@ -39,6 +39,27 @@ namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[6] =
+{
+  VisualFactoryCache::COLOR_SHADER,
+  VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER,
+  VisualFactoryCache::COLOR_SHADER_BORDERLINE,
+  VisualFactoryCache::COLOR_SHADER_ROUNDED_BORDERLINE,
+  VisualFactoryCache::COLOR_SHADER_BLUR_EDGE,
+  VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
+};
+
+// enum of required list when we select shader
+enum ColorVisualRequireFlag
+{
+  DEFAULT        = 0,
+  ROUNDED_CORNER = 1 << 0,
+  BORDERLINE     = 1 << 1,
+  BLUR           = 1 << 2,
+};
+} // unnamed namespace
 ColorVisualPtr ColorVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
 {
   ColorVisualPtr colorVisualPtr(new ColorVisual(factoryCache));
@@ -192,32 +213,52 @@ void ColorVisual::OnInitialize()
 Shader ColorVisual::GetShader()
 {
   Shader shader;
-  if(!EqualsZero(mBlurRadius) || mNeedBlurRadius)
+  VisualFactoryCache::ShaderType shaderType;
+
+  bool roundedCorner = IsRoundedCornerRequired();
+  bool borderline    = IsBorderlineRequired();
+  bool blur          = !EqualsZero(mBlurRadius) || mNeedBlurRadius;
+  int shaderTypeFlag = ColorVisualRequireFlag::DEFAULT;
+
+  if(roundedCorner)
   {
-    shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER_BLUR_EDGE);
-    if(!shader)
-    {
-      shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_BLUR_EDGE_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_BLUR_EDGE_SHADER_FRAG.data());
-      mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER_BLUR_EDGE, shader);
-    }
+    shaderTypeFlag |= ColorVisualRequireFlag::ROUNDED_CORNER;
   }
-  else if(!IsRoundedCornerRequired())
+  if(blur)
   {
-    shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER);
-    if(!shader)
-    {
-      shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
-      mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER, shader);
-    }
+    // If we use blur, just ignore borderline
+    borderline = false;
+    shaderTypeFlag |= ColorVisualRequireFlag::BLUR;
   }
-  else
+  if(borderline)
+  {
+    shaderTypeFlag |= ColorVisualRequireFlag::BORDERLINE;
+  }
+
+  shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+  shader = mFactoryCache.GetShader(shaderType);
+  if(!shader)
   {
-    shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER);
-    if(!shader)
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+    if(roundedCorner)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+    }
+    if(blur)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_BLUR 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BLUR 1\n";
+    }
+    if(borderline)
     {
-      shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_ROUNDED_CORNER_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_ROUNDED_CORNER_SHADER_FRAG.data());
-      mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER, shader);
+      vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
     }
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_COLOR_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
+    mFactoryCache.SaveShader(shaderType, shader);
   }
 
   return shader;
index b122359..896b095 100644 (file)
 #include <typeinfo>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-rounded-corner-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-rounded-corner-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-rounded-corner-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-rounded-corner-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-shader-vert.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
@@ -71,44 +64,35 @@ const char* const UNIFORM_ALIGNMENT_MATRIX_NAME("uAlignmentMatrix");
 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
 
-VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[][4] =
-  {
-    {VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
-     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
-     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
-     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER},
-    {VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
-     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
-     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
-     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER}};
-
-const std::string_view VERTEX_SHADER[] =
-  {
-    // vertex shader for gradient units as OBJECT_BOUNDING_BOX
-    SHADER_GRADIENT_VISUAL_BOUNDING_BOX_SHADER_VERT,
-
-    // vertex shader for gradient units as USER_SPACE
-    SHADER_GRADIENT_VISUAL_USER_SPACE_SHADER_VERT,
-
-    // vertex shader for gradient units as OBJECT_BOUNDING_BOX with corner radius
-    SHADER_GRADIENT_VISUAL_BOUNDING_BOX_ROUNDED_CORNER_SHADER_VERT,
-
-    // vertex shader for gradient units as USER_SPACE with corner radius
-    SHADER_GRADIENT_VISUAL_USER_SPACE_ROUNDED_CORNER_SHADER_VERT};
-
-const std::string_view FRAGMENT_SHADER[] =
-  {
-    // fragment shader for linear gradient
-    SHADER_GRADIENT_VISUAL_LINEAR_SHADER_FRAG,
-
-    // fragment shader for radial gradient
-    SHADER_GRADIENT_VISUAL_RADIAL_SHADER_FRAG,
-
-    // fragment shader for linear gradient with corner radius
-    SHADER_GRADIENT_VISUAL_LINEAR_ROUNDED_CORNER_SHADER_FRAG,
-
-    // fragment shader for radial gradient with corner radius
-    SHADER_GRADIENT_VISUAL_RADIAL_ROUNDED_CORNER_SHADER_FRAG};
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[16] =
+{
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
+};
+
+// enum of required list when we select shader
+enum GradientVisualRequireFlag
+{
+  DEFAULT        = 0,
+  ROUNDED_CORNER = 1 << 0,
+  BORDERLINE     = 1 << 1,
+  USER_SPACE     = 1 << 2,
+  RADIAL         = 1 << 3,
+};
 
 Dali::WrapMode::Type GetWrapMode(Toolkit::GradientVisual::SpreadMethod::Type spread)
 {
@@ -162,10 +146,10 @@ void GradientVisual::DoSetProperties(const Property::Map& propertyMap)
     Scripting::GetEnumerationProperty(*unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits);
   }
 
-  mGradientType = LINEAR;
+  mGradientType = Type::LINEAR;
   if(propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME))
   {
-    mGradientType = RADIAL;
+    mGradientType = Type::RADIAL;
   }
 
   if(NewGradient(mGradientType, propertyMap))
@@ -283,7 +267,7 @@ void GradientVisual::OnInitialize()
 
 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
 {
-  if(gradientType == LINEAR)
+  if(gradientType == Type::LINEAR)
   {
     Property::Value* startPositionValue = propertyMap.Find(Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME);
     Property::Value* endPositionValue   = propertyMap.Find(Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME);
@@ -299,7 +283,7 @@ bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propert
       return false;
     }
   }
-  else // type==RADIAL
+  else // type==Type::RADIAL
   {
     Property::Value* centerValue = propertyMap.Find(Toolkit::GradientVisual::Property::CENTER, CENTER_NAME);
     Property::Value* radiusValue = propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME);
@@ -363,13 +347,57 @@ bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propert
 
 Shader GradientVisual::GetShader()
 {
-  Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
-  int                                  roundedCorner = IsRoundedCornerRequired() ? 1 : 0;
-  VisualFactoryCache::ShaderType       shaderType    = SHADER_TYPE_TABLE[mGradientType][gradientUnits + roundedCorner * 2];
-  Shader                               shader        = mFactoryCache.GetShader(shaderType);
+  bool userspaceUnit  = (mGradient->GetGradientUnits() == Toolkit::GradientVisual::Units::USER_SPACE);
+  bool roundedCorner  = IsRoundedCornerRequired();
+  bool borderline     = IsBorderlineRequired();
+  bool radialGradient = (mGradientType == Type::RADIAL);
+
+  int  shaderTypeFlag = GradientVisualRequireFlag::DEFAULT;
+  if(roundedCorner)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::ROUNDED_CORNER;
+  }
+  if(borderline)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::BORDERLINE;
+  }
+  if(userspaceUnit)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::USER_SPACE;
+  }
+  if(radialGradient)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::RADIAL;
+  }
+
+  VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+  Shader                         shader     = mFactoryCache.GetShader(shaderType);
   if(!shader)
   {
-    shader = Shader::New(VERTEX_SHADER[gradientUnits + roundedCorner * 2], FRAGMENT_SHADER[mGradientType + roundedCorner * 2]);
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+
+    if(roundedCorner)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+    }
+    if(borderline)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+    }
+    if(radialGradient)
+    {
+      fragmentShaderPrefixList += "#define RADIAL 1\n";
+    }
+    if(userspaceUnit)
+    {
+      vertexShaderPrefixList   += "#define USER_SPACE 1\n";
+    }
+
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_GRADIENT_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_GRADIENT_VISUAL_SHADER_FRAG.data());
     mFactoryCache.SaveShader(shaderType, shader);
   }
 
index f8f7e5e..7f2cac7 100644 (file)
@@ -50,58 +50,77 @@ ImageVisualShaderFactory::~ImageVisualShaderFactory()
 {
 }
 
-Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner)
+Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline)
 {
   Shader shader;
-  if(atlasing)
+  VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
+  if(atlasing == TextureAtlas::ENABLED)
   {
-    if(defaultTextureWrapping)
+    if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP);
-      if(!shader)
+      shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
+    }
+    else
+    {
+      shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP;
+    }
+  }
+  else
+  {
+    if(roundedCorner == RoundedCorner::ENABLED)
+    {
+      if(borderline == Borderline::ENABLED)
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ATLAS_CLAMP_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader);
+        shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE;
+      }
+      else
+      {
+        shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER;
       }
     }
     else
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP);
-      if(!shader)
+      if(borderline == Borderline::ENABLED)
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ATLAS_VARIOUS_WRAP_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP, shader);
+        shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE;
       }
     }
   }
-  else
+
+  shader = factoryCache.GetShader(shaderType);
+  if(!shader)
   {
-    if(roundedCorner)
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+    if(atlasing == TextureAtlas::ENABLED)
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER);
-      if(!shader)
+      if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
+      {
+        fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n";
+      }
+      else
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_ROUNDED_CORNER_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ROUNDED_CORNER_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, shader);
+        fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP 1\n";
       }
     }
     else
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER);
-      if(!shader)
+      if(roundedCorner == RoundedCorner::ENABLED)
+      {
+        vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+        fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      }
+      if(borderline == Borderline::ENABLED)
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_NO_ATLAS_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER, shader);
+        vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
+        fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
       }
     }
+
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
+    shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+    factoryCache.SaveShader(shaderType, shader);
   }
 
   return shader;
@@ -121,7 +140,7 @@ std::string_view ImageVisualShaderFactory::GetFragmentShaderSource()
 {
   if(gFragmentShaderNoAtlas.empty())
   {
-    gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_NO_ATLAS_SHADER_FRAG.data();
+    gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data();
   }
   return gFragmentShaderNoAtlas;
 }
index 8ed50a6..604b49b 100644 (file)
@@ -30,11 +30,48 @@ namespace Toolkit
 namespace Internal
 {
 /**
+ * @brief Whether use texture with atlas, or not
+ */
+enum class TextureAtlas
+{
+  DISABLED = 0, ///< Image visual use ATLAS
+  ENABLED       ///< Image visual doesn't use ATLAS
+};
+
+/**
+ * @brief Whether apply to texture wraping in default, or not
+ */
+enum class DefaultTextureWrapMode
+{
+  DO_NOT_APPLY = 0, ///< Image visual doesn't apply to wraping texture in default
+  APPLY             ///< Image visual apply to wraping texture in default
+};
+
+/**
+ * @brief Whether use rounded corner, or not
+ */
+enum class RoundedCorner
+{
+  DISABLED = 0, ///< Image visual doesn't use rounded corner
+  ENABLED       ///< Image visual use rounded corner
+};
+
+/**
+ * @brief Whether use borderline, or not
+ */
+enum class Borderline
+{
+  DISABLED = 0, ///< Image visual doesn't use borderline
+  ENABLED       ///< Image visual use borderline
+};
+
+/**
  * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
  */
 class ImageVisualShaderFactory
 {
 public:
+
   /**
    * @brief Constructor
    */
@@ -51,8 +88,9 @@ public:
    * @param[in] atlasing Whether texture atlasing is applied.
    * @param[in] defaultTextureWrapping Whether the default texture wrap mode is applied.
    * @param[in] roundedCorner Whether the rounded corder is applied.
+   * @param[in] borderline Whether the borderline of visual is applied.
    */
-  Shader GetShader(VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner);
+  Shader GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline);
 
   /**
    * Request the default vertex shader source.
index 1c5f5e7..bbbab23 100644 (file)
@@ -978,9 +978,11 @@ Shader ImageVisual::GetShader()
     // Create and cache the standard shader
     shader = mImageVisualShaderFactory.GetShader(
       mFactoryCache,
-      mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
-      mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
-      IsRoundedCornerRequired());
+      mImpl->mFlags & Impl::IS_ATLASING_APPLIED ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+      mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
+      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+    );
   }
   else if(mImpl->mCustomShader)
   {
index bb8571d..bbee1d4 100644 (file)
@@ -376,7 +376,13 @@ void NPatchVisual::OnInitialize()
 {
   // Get basic geometry and shader
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
-  Shader   shader   = mImageVisualShaderFactory.GetShader(mFactoryCache, false, true, false);
+  Shader   shader   = mImageVisualShaderFactory.GetShader(
+    mFactoryCache,
+    TextureAtlas::DISABLED,
+    DefaultTextureWrapMode::APPLY,
+    RoundedCorner::DISABLED,
+    Borderline::DISABLED
+  );
 
   mImpl->mRenderer = Renderer::New(geometry, shader);
 
index dc148a2..b6f9520 100644 (file)
@@ -87,7 +87,13 @@ void SvgVisual::OnInitialize()
   Shader shader;
   if(!mImpl->mCustomShader)
   {
-    shader = mImageVisualShaderFactory.GetShader(mFactoryCache, mAttemptAtlasing, true, IsRoundedCornerRequired());
+    shader = mImageVisualShaderFactory.GetShader(
+      mFactoryCache,
+      mAttemptAtlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+      DefaultTextureWrapMode::APPLY,
+      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+    );
   }
   else
   {
index 2d42f93..53b5246 100644 (file)
@@ -119,16 +119,23 @@ Internal::Visual::Base::Impl::Impl(FittingMode fittingMode, Toolkit::Visual::Typ
   mTransform(),
   mMixColor(Color::WHITE),
   mControlSize(Vector2::ZERO),
+  mBorderlineWidth(0.0f),
+  mBorderlineColor(Color::BLACK),
+  mBorderlineOffset(0.0f),
   mCornerRadius(Vector4::ZERO),
   mCornerRadiusPolicy(1.0f),
   mDepthIndex(0.0f),
   mMixColorIndex(Property::INVALID_INDEX),
+  mBorderlineWidthIndex(Property::INVALID_INDEX),
+  mBorderlineColorIndex(Property::INVALID_INDEX),
+  mBorderlineOffsetIndex(Property::INVALID_INDEX),
   mCornerRadiusIndex(Property::INVALID_INDEX),
   mFittingMode(fittingMode),
   mFlags(0),
   mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
   mType(type),
-  mNeedCornerRadius(false)
+  mNeedCornerRadius(false),
+  mNeedBorderline(false)
 {
 }
 
index acb6805..52e0d98 100644 (file)
@@ -123,16 +123,23 @@ struct Base::Impl
   Transform                       mTransform;
   Vector4                         mMixColor;
   Size                            mControlSize;
+  float                           mBorderlineWidth;
+  Vector4                         mBorderlineColor;
+  float                           mBorderlineOffset;
   Vector4                         mCornerRadius;
   float                           mCornerRadiusPolicy;
   int                             mDepthIndex;
   Property::Index                 mMixColorIndex;
+  Property::Index                 mBorderlineWidthIndex;
+  Property::Index                 mBorderlineColorIndex;
+  Property::Index                 mBorderlineOffsetIndex;
   Property::Index                 mCornerRadiusIndex;
   FittingMode                     mFittingMode; //< How the contents should fit the view
   int                             mFlags;
   Toolkit::Visual::ResourceStatus mResourceStatus;
   const Toolkit::Visual::Type     mType;
   bool                            mNeedCornerRadius;
+  bool                            mNeedBorderline;
 };
 
 } // namespace Visual
index 528bc14..49b3120 100644 (file)
@@ -89,6 +89,14 @@ void Visual::Base::Initialize()
 
       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
     }
+    if(IsBorderlineRequired())
+    {
+      mImpl->mBorderlineWidthIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_WIDTH,  BORDERLINE_WIDTH,  mImpl->mBorderlineWidth);
+      mImpl->mBorderlineColorIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_COLOR,  BORDERLINE_COLOR,  mImpl->mBorderlineColor);
+      mImpl->mBorderlineOffsetIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_OFFSET, BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+    }
   }
 }
 
@@ -142,6 +150,18 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
       {
         matchKey = Property::Key(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE);
       }
+      else if(matchKey == BORDERLINE_WIDTH)
+      {
+        matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH);
+      }
+      else if(matchKey == BORDERLINE_COLOR)
+      {
+        matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_COLOR);
+      }
+      else if(matchKey == BORDERLINE_OFFSET)
+      {
+        matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET);
+      }
       else if(matchKey == CORNER_RADIUS)
       {
         matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS);
@@ -217,6 +237,33 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
           value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode);
         break;
       }
+      case Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
+      {
+        float width;
+        if(value.Get(width))
+        {
+          mImpl->mBorderlineWidth = width;
+        }
+        break;
+      }
+      case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
+      {
+        Vector4 color;
+        if(value.Get(color))
+        {
+          mImpl->mBorderlineColor = color;
+        }
+        break;
+      }
+      case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
+      {
+        float offset;
+        if(value.Get(offset))
+        {
+          mImpl->mBorderlineOffset = offset;
+        }
+        break;
+      }
       case Toolkit::DevelVisual::Property::CORNER_RADIUS:
       {
         if(value.GetType() == Property::VECTOR4)
@@ -388,6 +435,18 @@ void Visual::Base::CreatePropertyMap(Property::Map& map) const
     {
       mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mCornerRadiusIndex);
     }
+    if(mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+    }
+    if(mImpl->mBorderlineColorIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mBorderlineColor = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mBorderlineColorIndex);
+    }
+    if(mImpl->mBorderlineOffsetIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mBorderlineOffset = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineOffsetIndex);
+    }
   }
 
   DoCreatePropertyMap(map);
@@ -413,6 +472,10 @@ void Visual::Base::CreatePropertyMap(Property::Map& map) const
     mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT);
   map.Insert(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString);
 
+  map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+  map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
+  map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+
   map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius);
   map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast<int>(mImpl->mCornerRadiusPolicy));
 }
@@ -470,6 +533,16 @@ bool Visual::Base::IsRoundedCornerRequired() const
   return !(mImpl->mCornerRadius == Vector4::ZERO) || mImpl->mNeedCornerRadius;
 }
 
+bool Visual::Base::IsBorderlineRequired() const
+{
+  if(mImpl->mRenderer && mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+  {
+    // Update values from Renderer
+    mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+  }
+  return !EqualsZero(mImpl->mBorderlineWidth) || mImpl->mNeedBorderline;
+}
+
 void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
 {
   // May be overriden by derived class
@@ -824,7 +897,24 @@ Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
   Property::Index index = GetPropertyIndex(key);
   if(index == Property::INVALID_INDEX)
   {
-    if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
+    if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_WIDTH)  || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_WIDTH) ||
+       (key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_COLOR)  || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_COLOR) ||
+       (key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_OFFSET) || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_OFFSET))
+    {
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+      // Register borderline properties
+      mImpl->mBorderlineWidthIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_WIDTH, BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+      mImpl->mBorderlineColorIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_COLOR, BORDERLINE_COLOR, mImpl->mBorderlineColor);
+      mImpl->mBorderlineOffsetIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_OFFSET, BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+      mImpl->mNeedBorderline        = true;
+
+      index = mImpl->mRenderer.GetPropertyIndex(key);
+
+      // Change shader
+      UpdateShader();
+    }
+    else if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
     {
       // Register CORNER_RADIUS property
       mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
index c958992..8800ad8 100644 (file)
@@ -389,6 +389,13 @@ protected:
    */
   bool IsRoundedCornerRequired() const;
 
+  /**
+   * @brief Query whether the borderline of the visual requires to be rendered.
+   *
+   * @return Returns true if the outline is required, false otherwise.
+   */
+  bool IsBorderlineRequired() const;
+
 private:
   /**
    * Register the mix color uniform on the Renderer and store the property index.
index 418b10e..6e8f37d 100644 (file)
@@ -57,21 +57,34 @@ public:
   {
     COLOR_SHADER,
     COLOR_SHADER_ROUNDED_CORNER,
+    COLOR_SHADER_BORDERLINE,
+    COLOR_SHADER_ROUNDED_BORDERLINE,
     COLOR_SHADER_BLUR_EDGE,
+    COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
     BORDER_SHADER,
     BORDER_SHADER_ANTI_ALIASING,
-    GRADIENT_SHADER_LINEAR_USER_SPACE,
     GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
-    GRADIENT_SHADER_RADIAL_USER_SPACE,
-    GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
-    GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
     GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
-    GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+    GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
+    GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
+    GRADIENT_SHADER_LINEAR_USER_SPACE,
+    GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
+    GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
+    GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
     GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_USER_SPACE,
+    GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+    GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
     IMAGE_SHADER,
     IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
     IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
     IMAGE_SHADER_ROUNDED_CORNER,
+    IMAGE_SHADER_BORDERLINE,
+    IMAGE_SHADER_ROUNDED_BORDERLINE,
     NINE_PATCH_SHADER,
     NINE_PATCH_MASK_SHADER,
     TEXT_SHADER_MULTI_COLOR_TEXT,
index 9c9ca4b..53bcd1c 100644 (file)
@@ -75,6 +75,11 @@ const char* const OPACITY("opacity");
 // Fitting mode
 const char* const VISUAL_FITTING_MODE("visualFittingMode");
 
+// Border line
+const char* const BORDERLINE_WIDTH("borderlineWidth");
+const char* const BORDERLINE_COLOR("borderlineColor");
+const char* const BORDERLINE_OFFSET("borderlineOffset");
+
 // Corner radius
 const char* const CORNER_RADIUS("cornerRadius");
 const char* const CORNER_RADIUS_POLICY("cornerRadiusPolicy");
index 966e51f..470ded9 100644 (file)
@@ -59,6 +59,11 @@ extern const char* const OPACITY;
 // Fitting mode
 extern const char* const VISUAL_FITTING_MODE;
 
+// Border line
+extern const char* const BORDERLINE_WIDTH;
+extern const char* const BORDERLINE_COLOR;
+extern const char* const BORDERLINE_OFFSET;
+
 // Corner radius
 extern const char* const CORNER_RADIUS;
 extern const char* const CORNER_RADIUS_POLICY;
index 6717f5b..9a68ca1 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_IMPL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/adaptor-framework/style-change.h>
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/animation/time-period.h>
 #include <dali/public-api/events/long-press-gesture.h>
 #include <dali/public-api/events/pan-gesture.h>
 #include <dali/public-api/events/pinch-gesture.h>
@@ -251,6 +253,7 @@ public:
   DALI_INTERNAL void KeyboardEnter();
   /// @endcond
 
+
   // Signals
 
   /**
@@ -614,6 +617,21 @@ public: // API for derived classes to override
     return NULL;
   }
 
+  // Transition
+
+  /**
+   * @brief Retrieve visual property animations.
+   * This Control is a destination.
+   *
+   * @param[in] animation generated animation
+   * @param[in] source source control of the animation.
+   * @param[in] alphaFunction AlphaFunction of the animation
+   * @param[in] timePeriod TimePeriod of the animation
+   */
+  virtual void OnCreateTransitions(Dali::Animation& animation, Dali::Toolkit::Control source, AlphaFunction alphaFunction, TimePeriod timePeriod)
+  {
+  }
+
 private:
   /// @cond internal
 
index 51e26f7..71589e0 100644 (file)
@@ -138,7 +138,8 @@ public:
     JUSTIFY_CENTER,        ///< Items are positioned at the center of the container @SINCE_1_1.35
     JUSTIFY_FLEX_END,      ///< Items are positioned at the end of the container @SINCE_1_1.35
     JUSTIFY_SPACE_BETWEEN, ///< Items are positioned with equal space between the lines @SINCE_1_1.35
-    JUSTIFY_SPACE_AROUND   ///< Items are positioned with equal space before, between, and after the lines @SINCE_1_1.35
+    JUSTIFY_SPACE_AROUND,  ///< Items are positioned with equal space before, and after the lines @SINCE_1_1.35
+    JUSTIFY_SPACE_EVENLY   ///< Items are positioned with equal space before, between, and after the lines @SINCE_2_0.29
   };
 
   /**
index f31d0a0..89f0ec4 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 28;
+const unsigned int TOOLKIT_MICRO_VERSION = 30;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 76863a7..071b602 100644 (file)
@@ -31,6 +31,9 @@ SET( public_api_src_files
   ${public_api_src_dir}/image-loader/async-image-loader.cpp
   ${public_api_src_dir}/image-loader/sync-image-loader.cpp
   ${public_api_src_dir}/styling/style-manager.cpp
+  ${public_api_src_dir}/transition/transition-base.cpp
+  ${public_api_src_dir}/transition/transition-set.cpp
+  ${public_api_src_dir}/transition/transition.cpp
   ${public_api_src_dir}/focus-manager/keyboard-focus-manager.cpp
   ${public_api_src_dir}/dali-toolkit-version.cpp
   ${public_api_src_dir}/enums.cpp
@@ -143,6 +146,12 @@ SET( public_api_visuals_header_files
   ${public_api_src_dir}/visuals/text-visual-properties.h
 )
 
+SET( public_api_transition_header_files
+  ${public_api_src_dir}/transition/transition-base.h
+  ${public_api_src_dir}/transition/transition-set.h
+  ${public_api_src_dir}/transition/transition.h
+)
+
 SET( SOURCES ${SOURCES}
   ${public_api_src_files}
 )
@@ -162,6 +171,7 @@ SET( PUBLIC_API_HEADERS ${PUBLIC_API_HEADERS}
   ${public_api_slider_header_files}
   ${public_api_styling_header_files}
   ${public_api_text_controls_header_files}
+  ${public_api_transition_header_files}
   ${public_api_focus_manager_header_files}
   ${public_api_text_header_files}
   ${public_api_video_view_header_files}
diff --git a/dali-toolkit/public-api/transition/transition-base.cpp b/dali-toolkit/public-api/transition/transition-base.cpp
new file mode 100644 (file)
index 0000000..5e70e21
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/transition/transition-base.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition/transition-base-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+TransitionBase::TransitionBase() = default;
+
+TransitionBase::TransitionBase(Internal::TransitionBase* transitionBase)
+: BaseHandle(transitionBase)
+{
+}
+
+TransitionBase TransitionBase::New()
+{
+  Internal::TransitionBasePtr internal = Dali::Toolkit::Internal::TransitionBase::New();
+
+  return TransitionBase(internal.Get());
+}
+
+TransitionBase TransitionBase::DownCast(BaseHandle handle)
+{
+  return TransitionBase(dynamic_cast<Dali::Toolkit::Internal::TransitionBase*>(handle.GetObjectPtr()));
+}
+
+TransitionBase::~TransitionBase() = default;
+
+TransitionBase::TransitionBase(const TransitionBase& handle) = default;
+
+TransitionBase& TransitionBase::operator=(const TransitionBase& rhs) = default;
+
+TransitionBase::TransitionBase(TransitionBase&& rhs) = default;
+
+TransitionBase& TransitionBase::operator=(TransitionBase&& rhs) = default;
+
+void TransitionBase::SetTimePeriod(TimePeriod timePeriod)
+{
+  GetImplementation(*this).SetTimePeriod(timePeriod);
+}
+
+TimePeriod TransitionBase::GetTimePeriod() const
+{
+  return GetImplementation(*this).GetTimePeriod();
+}
+
+void TransitionBase::SetAlphaFunction(AlphaFunction alphaFunction)
+{
+  GetImplementation(*this).SetAlphaFunction(alphaFunction);
+}
+
+AlphaFunction TransitionBase::GetAlphaFunction() const
+{
+  return GetImplementation(*this).GetAlphaFunction();
+}
+
+void TransitionBase::TransitionWithChild(bool transitionWithChild)
+{
+  return GetImplementation(*this).TransitionWithChild(transitionWithChild);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/transition/transition-base.h b/dali-toolkit/public-api/transition/transition-base.h
new file mode 100644 (file)
index 0000000..9a274ac
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef DALI_TOOLKIT_TRANSITION_BASE_H
+#define DALI_TOOLKIT_TRANSITION_BASE_H
+
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/dali-toolkit-common.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/animation/time-period.h>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal DALI_INTERNAL
+{
+class TransitionBase;
+}
+
+/**
+ * @brief
+ *
+ * Transition provides continuous and seamless motions for the visually plausible scene change.
+ * And, TransitionBase is a base class for every Transition cases.
+ */
+class DALI_TOOLKIT_API TransitionBase : public BaseHandle
+{
+public:
+  /**
+   * @brief Creates an uninitialized TransitionBase; this can be initialized with TransitionBase::New().
+   *
+   * Calling member functions with an uninitialized TransitionBase handle is not allowed.
+   */
+  TransitionBase();
+
+  /**
+   * @brief Creates an initialized TransitionBase.
+   */
+  static TransitionBase New();
+
+  /**
+   * @brief Downcasts a handle to TransitionBase handle.
+   *
+   * If handle points to an TransitionBase object, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to an TransitionBase object or an uninitialized handle
+   */
+  static TransitionBase DownCast(BaseHandle handle);
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TransitionBase();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle
+   */
+  TransitionBase(const TransitionBase& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param[in] rhs A reference to the copied handle
+   * @return A reference to this
+   */
+  TransitionBase& operator=(const TransitionBase& rhs);
+
+  /**
+   * @brief Move constructor.
+   *
+   * @param[in] rhs A reference to the moved handle
+   */
+  TransitionBase(TransitionBase&& rhs);
+
+  /**
+   * @brief Move assignment operator.
+   *
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this handle
+   */
+  TransitionBase& operator=(TransitionBase&& rhs);
+
+  /**
+   * Set time period that contains delay and duration
+   * @param[in] timePeriod The time period for an animator.
+   */
+  void SetTimePeriod(TimePeriod timePeriod);
+
+  /**
+   * Get time period that contains delay and duration
+   */
+  TimePeriod GetTimePeriod() const;
+
+  /**
+   * @brief Sets the alpha function for an transition.
+   *
+   * This is applied to individual property transitions, if no further alpha functions are supplied.
+   * @param[in] alpha The alpha function
+   */
+  void SetAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * @brief Retrieves the alpha function for an transition.
+   *
+   * @return The alpha function
+   */
+  AlphaFunction GetAlphaFunction() const;
+
+  /**
+   * @brief A View could be transition with its child Views or without them.
+   */
+  void TransitionWithChild(bool transitionWithChild);
+
+public: // Not intended for use by Application developers
+  /// @cond internal
+  /**
+   * @brief This constructor is used by TransitionBase::New() methods.
+   * @param[in] transitionBase A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL TransitionBase(Internal::TransitionBase* transitionBase);
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TRANSITION_BASE_H
diff --git a/dali-toolkit/public-api/transition/transition-set.cpp b/dali-toolkit/public-api/transition/transition-set.cpp
new file mode 100644 (file)
index 0000000..fe8f33f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/transition/transition-set.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition/transition-set-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+TransitionSet::TransitionSet() = default;
+
+TransitionSet::TransitionSet(Internal::TransitionSet* transition)
+: BaseHandle(transition)
+{
+}
+
+TransitionSet TransitionSet::New()
+{
+  Internal::TransitionSetPtr internal = Dali::Toolkit::Internal::TransitionSet::New();
+
+  return TransitionSet(internal.Get());
+}
+
+TransitionSet TransitionSet::DownCast(BaseHandle handle)
+{
+  return TransitionSet(dynamic_cast<Dali::Toolkit::Internal::TransitionSet*>(handle.GetObjectPtr()));
+}
+
+TransitionSet::~TransitionSet() = default;
+
+TransitionSet::TransitionSet(const TransitionSet& handle) = default;
+
+TransitionSet& TransitionSet::operator=(const TransitionSet& rhs) = default;
+
+TransitionSet::TransitionSet(TransitionSet&& rhs) = default;
+
+TransitionSet& TransitionSet::operator=(TransitionSet&& rhs) = default;
+
+void TransitionSet::AddTransition(TransitionBase transition)
+{
+  if(transition)
+  {
+    Internal::TransitionBasePtr transitionBasePtr(&GetImplementation(transition));
+    GetImplementation(*this).AddTransition(transitionBasePtr);
+  }
+}
+
+TransitionBase TransitionSet::GetTransitionAt(uint32_t index) const
+{
+  Internal::TransitionBase* transitionBasePtr = GetImplementation(*this).GetTransitionAt(static_cast<uint32_t>(index));
+  return Dali::Toolkit::TransitionBase(transitionBasePtr);
+}
+
+uint32_t TransitionSet::GetTransitionCount() const
+{
+  return GetImplementation(*this).GetTransitionCount();
+}
+
+void TransitionSet::Play()
+{
+  GetImplementation(*this).Play();
+}
+
+TransitionSet::TransitionSetSignalType& TransitionSet::FinishedSignal()
+{
+  return GetImplementation(*this).FinishedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/transition/transition-set.h b/dali-toolkit/public-api/transition/transition-set.h
new file mode 100644 (file)
index 0000000..8df1ea5
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef DALI_TOOLKIT_TRANSITION_SET_H
+#define DALI_TOOLKIT_TRANSITION_SET_H
+
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/transition/transition-base.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <cstdint> // uint32_t, uint8_t
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal DALI_INTERNAL
+{
+class TransitionSet;
+}
+
+/**
+ * @brief
+ *
+ * TransitionSet is used to control lifetime of multiple Transitions.
+ * Transition could be played with multiple other transitions for a scene change.
+ * For the case, it is more useful to manage a group of transitions with same lifetime and a finished signal.
+ * TransitionSet provides a single Play call and Finished callback for the multiple traisitions those added on it.
+ */
+class DALI_TOOLKIT_API TransitionSet : public BaseHandle
+{
+public:
+  using TransitionSetSignalType = Signal<void(TransitionSet&)>; ///< TransitionSet finished signal type
+
+  /**
+   * @brief Creates an uninitialized TransitionSet; this can be initialized with TransitionSet::New().
+   *
+   * Calling member functions with an uninitialized TransitionSet handle is not allowed.
+   */
+  TransitionSet();
+
+  /**
+   * @brief Creates an initialized TransitionSet.
+   *
+   * @return A handle to a newly allocated Dali resource
+   * @note durationSeconds can not be negative.
+   */
+  static TransitionSet New();
+
+  /**
+   * @brief Downcasts a handle to TransitionSet handle.
+   *
+   * If handle points to an TransitionSet object, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to an TransitionSet object or an uninitialized handle
+   */
+  static TransitionSet DownCast(BaseHandle handle);
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TransitionSet();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle
+   */
+  TransitionSet(const TransitionSet& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param[in] rhs A reference to the copied handle
+   * @return A reference to this
+   */
+  TransitionSet& operator=(const TransitionSet& rhs);
+
+  /**
+   * @brief Move constructor.
+   *
+   * @param[in] rhs A reference to the moved handle
+   */
+  TransitionSet(TransitionSet&& rhs);
+
+  /**
+   * @brief Move assignment operator.
+   *
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this handle
+   */
+  TransitionSet& operator=(TransitionSet&& rhs);
+
+  /**
+   * @brief Add a TransitionBase on this TransitionSet.
+   *
+   * @param[in] transition TransitionBase to be added.
+   */
+  void AddTransition(TransitionBase transition);
+
+  /**
+   * @brief Retrieves a TransitionBase at the index.
+   *
+   * @return The TransitionBase of index
+   */
+  TransitionBase GetTransitionAt(uint32_t index) const;
+
+  /**
+   * @brief Retrieves the number of Transitions added in TransitionSet
+   *
+   * @return The number of Transitions
+   */
+  uint32_t GetTransitionCount() const;
+
+  /**
+   * @brief Play the transition.
+   * This method not make property animation instantly.
+   * Transition requires some world transform properties.
+   * The Transitions currently added on this TransitionSet are queued TransitionQueue
+   * and they are played at the end of this tick of event Thread
+   */
+  void Play();
+
+  /**
+   * @brief Connects to this signal to be notified when all TransitionSet's transitions have finished.
+   *
+   * @return A signal object to connect with
+   */
+  TransitionSetSignalType& FinishedSignal();
+
+public: // Not intended for use by Application developers
+  /// @cond internal
+  /**
+   * @brief This constructor is used by TransitionSet::New() methods.
+   * @param[in] transition A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL TransitionSet(Internal::TransitionSet* transition);
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TRANSITION_SET_H
diff --git a/dali-toolkit/public-api/transition/transition.cpp b/dali-toolkit/public-api/transition/transition.cpp
new file mode 100644 (file)
index 0000000..3e2f378
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/transition/transition.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition/transition-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+Transition::Transition() = default;
+
+Transition::Transition(Internal::Transition* transition)
+: TransitionBase(transition)
+{
+}
+
+Transition Transition::New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod)
+{
+  Internal::TransitionPtr internal = Dali::Toolkit::Internal::Transition::New(source, destination, timePeriod);
+
+  return Transition(internal.Get());
+}
+
+Transition Transition::DownCast(BaseHandle handle)
+{
+  return Transition(dynamic_cast<Dali::Toolkit::Internal::Transition*>(handle.GetObjectPtr()));
+}
+
+Transition::~Transition() = default;
+
+Transition::Transition(const Transition& handle) = default;
+
+Transition& Transition::operator=(const Transition& rhs) = default;
+
+Transition::Transition(Transition&& rhs) = default;
+
+Transition& Transition::operator=(Transition&& rhs) = default;
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/transition/transition.h b/dali-toolkit/public-api/transition/transition.h
new file mode 100644 (file)
index 0000000..634face
--- /dev/null
@@ -0,0 +1,124 @@
+#ifndef DALI_TOOLKIT_TRANSITION_H
+#define DALI_TOOLKIT_TRANSITION_H
+
+/*
+ * Copyright (c) 2021 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-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/transition/transition-base.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal DALI_INTERNAL
+{
+class Transition;
+}
+
+/**
+ * @brief
+ *
+ * Transition provides continuous and seamless motions between two Controls.
+ * This Transition generates property animation for transforms(position, scale, orientation), size, color, and opacity.
+ * And, if there are common renderer properties of source and destination Control, they also animated.
+ */
+class DALI_TOOLKIT_API Transition : public TransitionBase
+{
+public:
+  /**
+   * @brief Creates an uninitialized Transition; this can be initialized with Transition::New().
+   *
+   * Calling member functions with an uninitialized Transition handle is not allowed.
+   */
+  Transition();
+
+  /**
+   * @brief Creates an initialized Transition.
+   *
+   * @param[in] source Source
+   * @param[in] destination Destination
+   * @param[in] timePeriod The duration in seconds
+   * @return A handle to a newly allocated Dali resource
+   * @note durationSeconds can not be negative.
+   */
+  static Transition New(Dali::Toolkit::Control source, Dali::Toolkit::Control destination, TimePeriod timePeriod);
+
+  /**
+   * @brief Downcasts a handle to Transition handle.
+   *
+   * If handle points to an Transition object, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to an Transition object or an uninitialized handle
+   */
+  static Transition DownCast(BaseHandle handle);
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Transition();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle
+   */
+  Transition(const Transition& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param[in] rhs A reference to the copied handle
+   * @return A reference to this
+   */
+  Transition& operator=(const Transition& rhs);
+
+  /**
+   * @brief Move constructor.
+   *
+   * @param[in] rhs A reference to the moved handle
+   */
+  Transition(Transition&& rhs);
+
+  /**
+   * @brief Move assignment operator.
+   *
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this handle
+   */
+  Transition& operator=(Transition&& rhs);
+
+public: // Not intended for use by Application developers
+  /// @cond internal
+  /**
+   * @brief This constructor is used by Transition::New() methods.
+   * @param[in] transition A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL Transition(Internal::Transition* transition);
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TRANSITION_H
index 4552527..df6b9e4 100644 (file)
@@ -115,7 +115,8 @@ The possible values for this property are:
 | JUSTIFY_CENTER          | Items are positioned at the center of the container                        |
 | JUSTIFY_FLEX_END        | Items are positioned at the end of the container                           |
 | JUSTIFY_SPACE_BETWEEN   | Items are positioned with equal space between the lines                    |
-| JUSTIFY_SPACE_AROUND    | Items are positioned with equal space before, between, and after the lines |
+| JUSTIFY_SPACE_AROUND    | Items are positioned with equal space before, and after the lines          |
+| JUSTIFY_SPACE_EVENLY    | Items are positioned with equal space before, between, and after the lines |
  
 ### Usage
 
index 70ea699..7609a2c 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.0.28
+Version:    2.0.30
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT