Add borderline property for visual + Integrate some shaders in one 26/254026/27
authorEunki, Hong <eunkiki.hong@samsung.com>
Mon, 22 Feb 2021 09:37:36 +0000 (18:37 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Sat, 5 Jun 2021 02:29:31 +0000 (11:29 +0900)
Add borderline properies for visual
 - BORDERLINE_WIDTH "borderlineWidth" (float, default = 0.0)
   : Width of the borderline
 - BORDERLINE_COLOR "borderlineColor" (Vector4, default = Color::BLACK)
   : Color of the borderline
 - BORDERLINE_OFFSET "borderlineOffset" (float, default = 0.0)
   : Relative position offset from 'Real' borderline of visual.
     == 0.0f then half is inside, and half is outside of visual.
     == -1.0f then all borderline will be rendered inside of visual.
     == 1.0f then all borderline will be rendered outside of visual.

These three properties are animatable

Also, I integrate image / color / gradient visual shaders in one file.
Cause If I add above feature, the shader files need so many.

Change-Id: Ieeea3c1fd4703c5f446018ceffb46a7b715b36f1
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
43 files changed:
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-Visual.cpp
dali-toolkit/devel-api/visuals/visual-properties-devel.h
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/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

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 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 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
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 c9623a6..30a0dfe 100644 (file)
@@ -539,7 +539,13 @@ 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,
+    atlasing ? TextureAtlas::ENABLED : 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;