[dali_2.0.48] Merge branch 'devel/master' 58/265358/1 master
authorRichard Huang <r.huang@samsung.com>
Fri, 15 Oct 2021 09:44:48 +0000 (10:44 +0100)
committerRichard Huang <r.huang@samsung.com>
Fri, 15 Oct 2021 09:44:48 +0000 (10:44 +0100)
Change-Id: I4871e8e7cde644a4cae33801f9327536b97015a3

62 files changed:
automated-tests/resources/broken_l.9.png [new file with mode: 0755]
automated-tests/resources/broken_m.9.png [new file with mode: 0755]
automated-tests/resources/broken_s.9.png [new file with mode: 0755]
automated-tests/resources/test.tvg [new file with mode: 0644]
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-reflection.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-web-engine.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h
automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-KeyInputFocusManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
dali-toolkit/dali-toolkit.h
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/styling/style-manager-devel.cpp
dali-toolkit/devel-api/styling/style-manager-devel.h
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/gl-view/gl-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h [new file with mode: 0644]
dali-toolkit/internal/controls/web-view/web-view-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/graphics/shaders/gl-view.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gl-view.vert [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
dali-toolkit/internal/styling/style-manager-impl.cpp
dali-toolkit/internal/styling/style-manager-impl.h
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/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch-loader.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-factory-cache.cpp
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-impl.h
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/internal/visuals/visual-url.h
dali-toolkit/public-api/controls/gl-view/gl-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/gl-view/gl-view.h [new file with mode: 0644]
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/file.list
packaging/dali-toolkit.spec

diff --git a/automated-tests/resources/broken_l.9.png b/automated-tests/resources/broken_l.9.png
new file mode 100755 (executable)
index 0000000..48f6078
Binary files /dev/null and b/automated-tests/resources/broken_l.9.png differ
diff --git a/automated-tests/resources/broken_m.9.png b/automated-tests/resources/broken_m.9.png
new file mode 100755 (executable)
index 0000000..fd99939
Binary files /dev/null and b/automated-tests/resources/broken_m.9.png differ
diff --git a/automated-tests/resources/broken_s.9.png b/automated-tests/resources/broken_s.9.png
new file mode 100755 (executable)
index 0000000..d2fd5fa
Binary files /dev/null and b/automated-tests/resources/broken_s.9.png differ
diff --git a/automated-tests/resources/test.tvg b/automated-tests/resources/test.tvg
new file mode 100644 (file)
index 0000000..78bb48f
Binary files /dev/null and b/automated-tests/resources/test.tvg differ
index 8990a0f..b1aece3 100755 (executable)
@@ -78,6 +78,7 @@ SET(TC_SOURCES
   utc-Dali-ControlWrapper.cpp
   utc-Dali-DragAndDropDetector.cpp
   utc-Dali-NPatchUtilities.cpp
+  utc-Dali-GlView.cpp
 )
 
 # List of test harness files (Won't get parsed for test cases)
index e693098..ef389ed 100644 (file)
@@ -33,8 +33,9 @@ EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url)
     Dali::Vector<uint8_t> data;
     data.Resize(size);
     fseek(fp, 0, SEEK_SET);
-    fread(data.Begin(), size, sizeof(uint8_t), fp);
+    size_t realSize = fread(data.Begin(), sizeof(uint8_t), size, fp);
     fclose(fp);
+    data.Resize(realSize);
     buffer = EncodedImageBuffer::New(data);
   }
   return buffer;
index b85cf4d..e99de5c 100644 (file)
@@ -130,6 +130,7 @@ void TestGlAbstraction::Initialize()
     {"sTextureRect", GL_SAMPLER_2D, 1},
     {"sGloss", GL_SAMPLER_2D, 1},
     {"uColor", GL_FLOAT_VEC4, 1},
+    {"uActorColor", GL_FLOAT_VEC4, 1},
     {"uModelMatrix", GL_FLOAT_MAT4, 1},
     {"uModelView", GL_FLOAT_MAT4, 1},
     {"uMvpMatrix", GL_FLOAT_MAT4, 1},
index 0886719..d2d8b16 100644 (file)
@@ -379,8 +379,81 @@ GLenum GetBlendOp(Graphics::BlendOp blendOp)
     case Graphics::BlendOp::MAX:
       op = GL_MAX;
       break;
-
-      // @todo Add advanced blend equations
+    case Graphics::BlendOp::MULTIPLY:
+    {
+      op = GL_MULTIPLY;
+      break;
+    }
+    case Graphics::BlendOp::SCREEN:
+    {
+      op = GL_SCREEN;
+      break;
+    }
+    case Graphics::BlendOp::OVERLAY:
+    {
+      op = GL_OVERLAY;
+      break;
+    }
+    case Graphics::BlendOp::DARKEN:
+    {
+      op = GL_DARKEN;
+      break;
+    }
+    case Graphics::BlendOp::LIGHTEN:
+    {
+      op = GL_LIGHTEN;
+      break;
+    }
+    case Graphics::BlendOp::COLOR_DODGE:
+    {
+      op = GL_COLORDODGE;
+      break;
+    }
+    case Graphics::BlendOp::COLOR_BURN:
+    {
+      op = GL_COLORBURN;
+      break;
+    }
+    case Graphics::BlendOp::HARD_LIGHT:
+    {
+      op = GL_HARDLIGHT;
+      break;
+    }
+    case Graphics::BlendOp::SOFT_LIGHT:
+    {
+      op = GL_SOFTLIGHT;
+      break;
+    }
+    case Graphics::BlendOp::DIFFERENCE:
+    {
+      op = GL_DIFFERENCE;
+      break;
+    }
+    case Graphics::BlendOp::EXCLUSION:
+    {
+      op = GL_EXCLUSION;
+      break;
+    }
+    case Graphics::BlendOp::HUE:
+    {
+      op = GL_HSL_HUE;
+      break;
+    }
+    case Graphics::BlendOp::SATURATION:
+    {
+      op = GL_HSL_SATURATION;
+      break;
+    }
+    case Graphics::BlendOp::COLOR:
+    {
+      op = GL_HSL_COLOR;
+      break;
+    }
+    case Graphics::BlendOp::LUMINOSITY:
+    {
+      op = GL_HSL_LUMINOSITY;
+      break;
+    }
   }
   return op;
 }
index 8493992..25c09b5 100644 (file)
@@ -40,6 +40,7 @@ static const std::vector<UniformData> UNIFORMS =
     UniformData("sTextureRect", Property::Type::FLOAT),
     UniformData("sGloss", Property::Type::FLOAT),
     UniformData("uColor", Property::Type::VECTOR4),
+    UniformData("uActorColor", Property::Type::VECTOR4),
     UniformData("uModelMatrix", Property::Type::MATRIX),
     UniformData("uModelView", Property::Type::MATRIX),
     UniformData("uMvpMatrix", Property::Type::MATRIX),
index 8f8853c..cd863b9 100755 (executable)
@@ -2056,7 +2056,7 @@ std::string WebEngine::GetUrl() const
   return Internal::Adaptor::GetImplementation( *this ).GetUrl();
 }
 
-NativeImageInterfacePtr WebEngine::GetNativeImageSource()
+NativeImageSourcePtr WebEngine::GetNativeImageSource()
 {
   Any source;
   Dali::NativeImageSourcePtr sourcePtr = Dali::NativeImageSource::New( source );
index dc7a206..9044964 100644 (file)
@@ -54,6 +54,7 @@ public:
   FocusChangeSignalType mFocusChangeSignal;
   ResizeSignalType      mResizeSignal;
   int                   mRotationAngle;
+  bool                  mVisible;
   DevelWindow::VisibilityChangedSignalType mVisibilityChangedSignal;
 };
 
index d0a3e4f..b8cc1bc 100644 (file)
@@ -48,6 +48,7 @@ Window::Window( const PositionSize& positionSize )
   mFocusChangeSignal(),
   mResizeSignal(),
   mRotationAngle(90), // dummy angle for test coverage
+  mVisible(true),
   mVisibilityChangedSignal()
 {
 }
@@ -183,6 +184,12 @@ void Window::Raise()
 void Window::Hide()
 {
   GetImplementation( *this ).mVisibilityChangedSignal.Emit( *this, false );
+  GetImplementation( *this ).mVisible = false;
+}
+
+bool Window::IsVisible() const
+{
+  return GetImplementation( *this ).mVisible;
 }
 
 FocusChangeSignalType& Window::FocusChangeSignal()
index a696684..d102f6a 100644 (file)
@@ -77,6 +77,7 @@ public:
   Vector4 GetBackgroundColor() const;
   void Raise();
   void Hide();
+  bool IsVisible() const;
   FocusChangeSignalType& FocusChangeSignal();
   KeyEventSignalType& KeyEventSignal();
   TouchEventSignalType& TouchedSignal();
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp
new file mode 100644 (file)
index 0000000..9f74b72
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <unistd.h>
+#include <thread>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+// Positive test case for a method
+int UtcDaliGlViewNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliGlViewNew");
+  GlView view = GlView::New(GlView::ColorFormat::RGBA8888);
+  DALI_TEST_CHECK( view );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGlViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliGlViewDownCast");
+
+  GlView view = GlView::New(GlView::ColorFormat::RGB888);
+  BaseHandle handle(view);
+
+  Toolkit::GlView view2 = Toolkit::GlView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( view2 );
+  DALI_TEST_CHECK( view == view2 );
+  END_TEST;
+}
+
+int UtcDaliGlViewCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewCopyAndAssignment");
+
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+  DALI_TEST_CHECK( view );
+
+  GlView copy( view );
+  DALI_TEST_CHECK( view == copy );
+
+  GlView assign;
+  DALI_TEST_CHECK( !assign );
+
+  assign = copy;
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliGlViewMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewMoveAssignment");
+
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+  DALI_TEST_EQUALS( 1, view.GetBaseObject().ReferenceCount(), TEST_LOCATION );
+
+  GlView moved;
+  moved = std::move( view );
+  DALI_TEST_CHECK( moved );
+  DALI_TEST_EQUALS( 1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION );
+  DALI_TEST_CHECK( !view );
+
+  END_TEST;
+}
+
+int UtcDaliGlViewSetGraphicsConfigGles20N(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewSetGraphicsConfigGles20");
+  GlView view;
+  try
+  {
+    view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+    DALI_TEST_CHECK(false);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true);
+  }
+  END_TEST;
+}
+
+int UtcDaliGlViewSetGraphicsConfigGles30(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewSetGraphicsConfigGles30");
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+
+  try
+  {
+    view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_3_0);
+    DALI_TEST_CHECK(true);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(false);
+  }
+  END_TEST;
+}
+
+int UtcDaliGlViewRenderingMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewRenderingMode");
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+
+  view.SetRenderingMode(GlView::RenderingMode::ON_DEMAND);
+
+  GlView::RenderingMode mode = view.GetRenderingMode();
+
+  DALI_TEST_EQUALS( GlView::RenderingMode::ON_DEMAND, mode, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliGlViewOnSizeSet(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewOnSizeSet");
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+
+
+  application.GetScene().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 size( 200.0f, 300.0f, 0.0f );
+  view.SetProperty( Actor::Property::SIZE, size );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ), size, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+// Internal callback function
+void glInit(void)
+{
+}
+
+int glRenderFrame(void)
+{
+  static unsigned int retFlag = 0;
+  return retFlag++;
+}
+
+void glTerminate(void)
+{
+}
+
+void resizeCB(Vector2 size)
+{
+}
+
+int UtcDaliGlViewRegisterGlCallbackN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewRegisterGlCallback");
+  GlView view;
+
+  try
+  {
+    view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+    DALI_TEST_CHECK(false);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true);
+  }
+  END_TEST;
+}
+
+int UtcDaliGlViewSetResizeCallbackN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewSetResizeCallback");
+  GlView view;
+
+  try
+  {
+    view.SetResizeCallback(Dali::MakeCallback(resizeCB));
+    DALI_TEST_CHECK(false);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true);
+  }
+  END_TEST;
+}
+
+int UtcDaliGlViewRenderOnce(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewRenderOnce");
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+
+  try
+  {
+    view.RenderOnce();
+    DALI_TEST_CHECK(true);
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(false);
+  }
+  END_TEST;
+}
+
+int UtcDaliGlViewWindowVisibilityChanged(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewWindowVisibilityChanged");
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+  application.GetScene().Add( view );
+  view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS);
+  view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+  view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+  view.SetResizeCallback(Dali::MakeCallback(resizeCB));
+
+  application.SendNotification();
+  application.Render();
+
+  Window window = DevelWindow::Get( view );
+  window.Hide();
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(true);
+  END_TEST;
+}
+
+int UtcDaliGlViewOnScene(void)
+{
+  ToolkitTestApplication application;
+
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+
+  //Onscene
+  application.GetScene().Add( view );
+  view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS);
+  view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+  view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+
+  application.SendNotification();
+  application.Render();
+
+  //Offscene
+  application.GetScene().Remove(view);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(true);
+  END_TEST;
+}
+
+int UtcDaliGlViewControlVisibilityChanged(void)
+{
+  ToolkitTestApplication application;
+
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+  application.GetScene().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  view.SetProperty( Actor::Property::VISIBLE, false );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK(view.GetCurrentProperty<bool>(Actor::Property::VISIBLE) == false);
+
+  view.SetProperty( Actor::Property::VISIBLE, true );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK(view.GetCurrentProperty<bool>(Actor::Property::VISIBLE) == true);
+
+  END_TEST;
+}
+
+int UtcDaliGlViewResize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGlViewResize");
+  GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888);
+
+  application.GetScene().Add( view );
+  view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0);
+  view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate));
+  view.SetResizeCallback(Dali::MakeCallback(resizeCB));
+  view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  view.SetProperty(Actor::Property::SIZE, Vector2(360.0f, 360.0f));
+
+  application.SendNotification();
+  application.Render();
+
+  //To GlViewRenderThread can recognize Resize signal the main thread have to sleep.
+  std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(true);
+  END_TEST;
+}
index 0450040..e8dd77e 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/public-api/image-loader/image.h>
 #include <dali-toolkit/public-api/image-loader/image-url.h>
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
 
 #include <test-native-image.h>
 #include <test-encoded-image-buffer.h>
@@ -61,6 +62,13 @@ const char* TEST_IMAGE_FILE_NAME2 =  "gallery_image_02.jpg";
 const char* TEST_IMAGE_1 = TEST_RESOURCE_DIR "/TB-gloss.png";
 const char* TEST_IMAGE_2 = TEST_RESOURCE_DIR "/tb-norm.png";
 
+const char* TEST_BROKEN_IMAGE_DEFAULT = TEST_RESOURCE_DIR "/broken.png";
+const char* TEST_BROKEN_IMAGE_S = TEST_RESOURCE_DIR "/broken_s.9.png";
+const char* TEST_BROKEN_IMAGE_M = TEST_RESOURCE_DIR "/broken_m.9.png";
+const char* TEST_BROKEN_IMAGE_L = TEST_RESOURCE_DIR "/broken_l.9.png";
+const char* TEST_BROKEN_IMAGE_01 =  TEST_RESOURCE_DIR "/button-up.9.png";
+const char* TEST_BROKEN_IMAGE_02 =  TEST_RESOURCE_DIR "/heartsframe.9.png";
+
 // resolution: 34*34, pixel format: RGBA8888
 static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
 // resolution: 600*600, pixel format: RGB888
@@ -2883,6 +2891,116 @@ int UtcDaliImageViewSvgRasterizationFailure(void)
   END_TEST;
 }
 
+int UtcDaliImageViewTVGLoading(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing TVG image loading");
+
+  {
+    ImageView imageView = ImageView::New( );
+
+    imageView.SetImage( TEST_RESOURCE_DIR "/test.tvg" );
+
+    application.GetScene().Add( imageView );
+    DALI_TEST_CHECK( imageView );
+    Vector3 naturalSize = imageView.GetNaturalSize();
+
+    DALI_TEST_EQUALS( naturalSize.width, 100.0f, TEST_LOCATION );
+    DALI_TEST_EQUALS( naturalSize.height, 100.0f, TEST_LOCATION );
+  }
+  END_TEST;
+}
+int UtcDaliImageViewImageLoadFailure01(void)
+{
+  ToolkitTestApplication application;
+
+  Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::SMALL, TEST_BROKEN_IMAGE_S);
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::NORMAL, TEST_BROKEN_IMAGE_M);
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::LARGE, TEST_BROKEN_IMAGE_L);
+
+  std::string brokenUrl;
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::SMALL);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_S, brokenUrl, TEST_LOCATION);
+
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::NORMAL);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_M, brokenUrl, TEST_LOCATION);
+
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::LARGE);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_L, brokenUrl, TEST_LOCATION);
+
+  ImageView imageView = ImageView::New("invalidUrl.png");
+  imageView.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+
+  application.GetScene().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewImageLoadFailure02(void)
+{
+  ToolkitTestApplication application;
+
+  Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::SMALL, TEST_BROKEN_IMAGE_DEFAULT);
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::NORMAL, TEST_BROKEN_IMAGE_M);
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::LARGE, TEST_BROKEN_IMAGE_L);
+
+  std::string brokenUrl;
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::SMALL);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_DEFAULT, brokenUrl, TEST_LOCATION);
+
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::NORMAL);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_M, brokenUrl, TEST_LOCATION);
+
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::LARGE);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_L, brokenUrl, TEST_LOCATION);
+
+  ImageView imageView = ImageView::New("invalidUrl.png");
+  imageView.SetProperty( Actor::Property::SIZE, Vector2( 30.f, 30.f ) );
+  application.GetScene().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewImageLoadFailure03(void)
+{
+  ToolkitTestApplication application;
+
+  Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::SMALL, TEST_BROKEN_IMAGE_01);
+  DevelStyleManager::SetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::NORMAL, TEST_BROKEN_IMAGE_02);
+
+  std::string brokenUrl;
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::SMALL);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_01, brokenUrl, TEST_LOCATION);
+
+  brokenUrl = DevelStyleManager::GetBrokenImageUrl(styleManager, DevelStyleManager::BrokenImageType::NORMAL);
+  DALI_TEST_EQUALS( TEST_BROKEN_IMAGE_02, brokenUrl, TEST_LOCATION);
+
+  ImageView imageView = ImageView::New("invalidUrl.png");
+  imageView.SetProperty( Actor::Property::SIZE, Vector2( 100.f, 100.f ) );
+  application.GetScene().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
 namespace
 {
 
index 5a0cf33..18345a3 100644 (file)
@@ -20,6 +20,7 @@
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali/integration-api/events/key-event-integ.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
 #include <dali/devel-api/common/stage-devel.h>
 
@@ -305,6 +306,53 @@ int UtcDaliKeyInputFocusManagerKeyEventPropagation02(void)
   END_TEST;
 }
 
+int UtcDaliKeyInputFocusManagerDispatchKeyEvents(void)
+{
+
+  ToolkitTestApplication application;
+  Integration::Scene stage = application.GetScene();
+
+  tet_infoline("Test KeyEvents propagation. If DISPATCH_KEY_EVENTS property is false, the KeyEvent is also not received.");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  dummy1.SetProperty( Actor::Property::SIZE, Vector2(100.0f, 100.0f) );
+  KeyEventCallback callback1( false );
+  dummy1.KeyEventSignal().Connect( &callback1, &KeyEventCallback::Callback );
+  stage.Add( dummy1 );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  dummy2.SetProperty( Actor::Property::SIZE, Vector2(100.0f, 100.0f) );
+  KeyEventCallback callback2( false );
+  dummy2.KeyEventSignal().Connect( &callback2, &KeyEventCallback::Callback );
+  // dummy2 set DISPATCH_KEY_EVENTS property to false.
+  dummy2.SetProperty( Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS, false);
+  dummy1.Add( dummy2 );
+
+  DummyControl dummy3 = DummyControl::New(true);
+  Impl::DummyControl& dummy3Impl = static_cast<Impl::DummyControl&>(dummy3.GetImplementation());
+  dummy3.SetProperty( Actor::Property::SIZE, Vector2(100.0f, 100.0f) );
+  KeyEventCallback callback3( false );
+  dummy3.KeyEventSignal().Connect( &callback3, &KeyEventCallback::Callback );
+  dummy2.Add( dummy3 );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost );
+
+  manager.SetFocus( dummy3 );
+  DALI_TEST_CHECK( dummy3Impl.keyInputFocusGained );
+
+  Integration::KeyEvent event( "a", "", "a", 0, 0, 0, Integration::KeyEvent::UP, "", "", Device::Class::TOUCH, Device::Subclass::NONE );
+  application.ProcessEvent(event);
+
+  DALI_TEST_CHECK( !callback1.mIsCalled );
+  DALI_TEST_CHECK( !callback2.mIsCalled );
+  DALI_TEST_CHECK( !callback3.mIsCalled );
+
+  END_TEST;
+}
+
 int UtcDaliKeyInputFocusManagerGetCurrentFocusControl(void)
 {
   ToolkitTestApplication application;
index bd389ad..d1a2e56 100644 (file)
@@ -4352,6 +4352,242 @@ int UtcDaliVisualBorderline(void)
   END_TEST;
 }
 
+int UtcDaliVisualBorderlineBlendModeTest(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualBorderlineBlendModeTest" );
+  VisualFactory factory = VisualFactory::Get();
+
+  // Case 1 : Test which doesn't support borderline feature.
+  {
+    tet_printf("Test Unsupported visual type\n");
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::BORDER);
+    propertyMap.Insert(BorderVisual::Property::COLOR, Color::BLUE);
+    propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+    Visual::Base borderVisual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, borderVisual );
+    actor.SetProperty( Actor::Property::SIZE, Vector2( 2000.f, 2000.f ) );
+    actor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
+    application.GetScene().Add(actor);
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    Renderer renderer = actor.GetRendererAt(0);
+
+    Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // Visual::BORDER doesn't support BORDERLINE. BlendMode is AUTO.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+    application.GetScene().Remove(actor);
+  }
+
+  // Case 2 : Test which support borderline feature.
+  {
+    tet_printf("Test normal case\n");
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
+    propertyMap.Insert(ColorVisual::Property::MIX_COLOR, Color::BLUE);
+    propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+    Visual::Base colorVisual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, colorVisual );
+    actor.SetProperty( Actor::Property::SIZE, Vector2( 2000.f, 2000.f ) );
+    actor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
+    application.GetScene().Add(actor);
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    Renderer renderer = actor.GetRendererAt(0);
+
+    Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // Visual::COLOR support BORDERLINE. BlendMode is ON_WITHOUT_CULL.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON_WITHOUT_CULL, TEST_LOCATION );
+
+    application.GetScene().Remove(actor);
+  }
+
+  // Case 3 : Test which animated borderline.
+  {
+    tet_printf("Test borderline animate case\n");
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
+    propertyMap.Insert(ColorVisual::Property::MIX_COLOR, Color::BLUE);
+    Visual::Base colorVisual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, colorVisual );
+    actor.SetProperty( Actor::Property::SIZE, Vector2( 2000.f, 2000.f ) );
+    actor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
+    application.GetScene().Add(actor);
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    Renderer renderer = actor.GetRendererAt(0);
+
+    Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // BlendMode is AUTO.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+    Animation animation = Animation::New(0.1f);
+    animation.AnimateTo( DevelControl::GetVisualProperty(actor, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), 1.0f );
+    animation.Play();
+
+    application.SendNotification();
+    application.Render();
+    application.Render(101u); // End of animation
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // BlendMode is ON_WITHOUT_CULL.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON_WITHOUT_CULL, TEST_LOCATION );
+
+    Animation revanimation = Animation::New(0.1f);
+    revanimation.AnimateTo( DevelControl::GetVisualProperty(actor, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), 0.0f );
+    revanimation.Play();
+
+    application.SendNotification();
+    application.Render();
+    application.Render(101u); // End of animation
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // BlendMode is still ON_WITHOUT_CULL.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON_WITHOUT_CULL, TEST_LOCATION );
+
+    application.GetScene().Remove(actor);
+  }
+
+  // Case 4 : Test which animated corner radius occur.
+  {
+    tet_printf("Test borderline animate case\n");
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::COLOR);
+    propertyMap.Insert(ColorVisual::Property::MIX_COLOR, Color::BLUE);
+    propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+    Visual::Base colorVisual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, colorVisual );
+    actor.SetProperty( Actor::Property::SIZE, Vector2( 2000.f, 2000.f ) );
+    actor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
+    application.GetScene().Add(actor);
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    Renderer renderer = actor.GetRendererAt(0);
+
+    Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // BlendMode is ON_WITHOUT_CULL.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON_WITHOUT_CULL, TEST_LOCATION );
+
+    Animation animation = Animation::New(0.1f);
+    animation.AnimateTo( DevelControl::GetVisualProperty(actor, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), Vector4(1.0f, 1.0f, 1.0f, 1.0f) );
+    animation.Play();
+
+    application.SendNotification();
+    application.Render();
+    application.Render(101u); // End of animation
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    // BlendMode is ON_WITHOUT_CULL.
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON_WITHOUT_CULL, TEST_LOCATION );
+
+    application.GetScene().Remove(actor);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualBorderlineColorAnimateTest(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualBorderlineColorAnimateTest color" );
+
+  TestGraphicsController& graphics = application.GetGraphicsController();
+  static std::vector<UniformData> customUniforms =
+  {
+    UniformData("mixColor", Property::Type::VECTOR3),
+    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),
+  };
+  graphics.AddCustomUniforms(customUniforms);
+
+  {
+    const Vector3 INITIAL_MIX_COLOR( 1.0f,0.0f,1.0f );
+    const float   INITIAL_MIX_OPACITY( 0.5f );
+    const Vector4 INITIAL_BORDERLINE_COLOR( 0.0f,1.0f,0.0f,1.0f );
+    const float   INITIAL_ACTOR_OPACITY( 1.0f );
+    const Vector3 TARGET_MIX_COLOR( 1.0f, 0.0f, 0.0f );
+    const float   TARGET_MIX_OPACITY( 0.8f );
+    const Vector4 TARGET_BORDERLINE_COLOR( 1.0f, 0.0f, 1.0f, 0.2f);
+    const float   TARGET_ACTOR_OPACITY( 0.5f );
+
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+    propertyMap.Insert(Visual::Property::MIX_COLOR, INITIAL_MIX_COLOR);
+    propertyMap.Insert(Visual::Property::OPACITY, INITIAL_MIX_OPACITY);
+    propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+    propertyMap.Insert(DevelVisual::Property::BORDERLINE_COLOR, INITIAL_BORDERLINE_COLOR);
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+    actor.SetProperty( Actor::Property::SIZE, Vector2( 2000.f, 2000.f ) );
+    actor.SetProperty( Actor::Property::OPACITY, INITIAL_ACTOR_OPACITY );
+    actor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER);
+    application.GetScene().Add(actor);
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    Animation animation = Animation::New(4.0f);
+    animation.AnimateTo( DevelControl::GetVisualProperty(actor, DummyControl::Property::TEST_VISUAL, Visual::Property::MIX_COLOR), TARGET_MIX_COLOR );
+    animation.AnimateTo( DevelControl::GetVisualProperty(actor, DummyControl::Property::TEST_VISUAL, Visual::Property::OPACITY), TARGET_MIX_OPACITY);
+    animation.AnimateTo( DevelControl::GetVisualProperty(actor, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), TARGET_BORDERLINE_COLOR );
+    animation.AnimateTo( Property(actor, Actor::Property::OPACITY), TARGET_ACTOR_OPACITY);
+    animation.Play();
+
+    TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+
+    application.SendNotification();
+    application.Render(0);
+    application.Render(2000u); // halfway point
+    application.SendNotification();
+
+    Vector3 halfwayMixColor        = (INITIAL_MIX_COLOR        + TARGET_MIX_COLOR       ) * 0.5f;
+    float   halfwayMixOpacity      = (INITIAL_MIX_OPACITY      + TARGET_MIX_OPACITY     ) * 0.5f;
+    Vector4 halfwayBorderlineColor = (INITIAL_BORDERLINE_COLOR + TARGET_BORDERLINE_COLOR) * 0.5f;
+    float   halfwayActorOpacity    = (INITIAL_ACTOR_OPACITY    + TARGET_ACTOR_OPACITY   ) * 0.5f;
+    halfwayMixOpacity *= halfwayActorOpacity;
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector3>("mixColor", halfwayMixColor), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector4>("uColor", Vector4(1.0f, 1.0f, 1.0f, halfwayMixOpacity)), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector4>("uActorColor", Vector4(1.0f, 1.0f, 1.0f, halfwayActorOpacity)), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector4>("borderlineColor", halfwayBorderlineColor), true, TEST_LOCATION );
+
+    application.Render(2001u); // go past end
+    application.SendNotification(); // Trigger signals
+
+    DALI_TEST_EQUALS( actor.GetCurrentProperty< Vector4 >( Actor::Property::COLOR ), Vector4(1.0f, 1.0f, 1.0f, TARGET_ACTOR_OPACITY), TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector3>("mixColor", TARGET_MIX_COLOR), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector4>("uColor", Vector4(1.0f, 1.0f, 1.0f, TARGET_MIX_OPACITY * TARGET_ACTOR_OPACITY) ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector4>("uActorColor", Vector4(1.0f, 1.0f, 1.0f, TARGET_ACTOR_OPACITY)), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( glAbstraction.CheckUniformValue<Vector4>("borderlineColor", TARGET_BORDERLINE_COLOR ), true, TEST_LOCATION );
+
+    actor.Unparent();
+  }
+
+  END_TEST;
+}
 
 int UtcDaliColorVisualBlurRadius(void)
 {
index 1ec7fa3..99621c8 100644 (file)
@@ -28,6 +28,7 @@
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/controls/flex-container/flex-container.h>
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
 #include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
 #include <dali-toolkit/public-api/controls/progress-bar/progress-bar.h>
index 51cf1cc..36b83f9 100644 (file)
@@ -184,7 +184,14 @@ enum
    * @brief Set of accessibility attributes describing object in accessibility hierarchy
    * @details Name "accessibilityAttributes", type Property::MAP
    */
-  ACCESSIBILITY_ATTRIBUTES
+  ACCESSIBILITY_ATTRIBUTES,
+
+  /**
+   * @brief Whether a Control and its descendants can emit key signals.
+   * @details Name "dispatchKeyEvents", type Property::BOOLEAN
+   * @note If a control's dispatchKeyEvents is set to false, then it's children will not emit a key event signal either.
+   */
+  DISPATCH_KEY_EVENTS,
 };
 
 } // namespace Property
index 29f0e8b..cc96d45 100644 (file)
@@ -30,6 +30,26 @@ const Property::Map GetConfigurations(StyleManager styleManager)
   return GetImpl(styleManager).GetConfigurations();
 }
 
+void SetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl)
+{
+  return GetImpl(styleManager).SetBrokenImageUrl(brokenImageType, brokenImageUrl);
+}
+
+std::string GetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType)
+{
+  return GetImpl(styleManager).GetBrokenImageUrl(brokenImageType);
+}
+
+std::vector<std::string> GetBrokenImageUrlList(StyleManager styleManager)
+{
+  return GetImpl(styleManager).GetBrokenImageUrlList();
+}
+
+BrokenImageChangedSignalType& BrokenImageChangedSignal(StyleManager styleManager)
+{
+  return GetImpl(styleManager).BrokenImageChangedSignal();
+}
+
 } // namespace DevelStyleManager
 
 } // namespace Toolkit
index efcff7d..f1e05d7 100644 (file)
@@ -28,6 +28,18 @@ namespace Toolkit
 namespace DevelStyleManager
 {
 /**
+ * @brief The Type of BrokenImage
+ */
+enum class BrokenImageType
+{
+  SMALL,
+  NORMAL,
+  LARGE
+};
+
+using BrokenImageChangedSignalType = Signal<void(StyleManager)>;
+
+/**
  * @brief Gets all currently defined configurations.
  *
  * @pre The Builder has been initialized.
@@ -36,6 +48,43 @@ namespace DevelStyleManager
 **/
 DALI_TOOLKIT_API const Property::Map GetConfigurations(StyleManager styleManager);
 
+/**
+   * @brief Sets an image to be used when a visual has failed to correctly render
+   * @param[in] styleManager The instance of StyleManager
+   * @param[in] brokenImageType The type of broken image
+   * @param[in] brokenImageUrl The broken image url
+   */
+DALI_TOOLKIT_API void SetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl);
+
+/**
+   * @brief Gets an image to be used when a visual has failed to correctly render
+   * @param[in] styleManager The instance of StyleManager
+   * @param[in] brokenImageType BrokenImage type
+   */
+DALI_TOOLKIT_API std::string GetBrokenImageUrl(StyleManager styleManager, DevelStyleManager::BrokenImageType brokenImageType);
+
+/**
+ * @brief Get the Broken Image Url List
+ *
+ * This list is broken images stored in order of SMALL, NORMAL, and LARGE values except if the value is empty.
+ * This API just makes the list without comparing size, so the application must set a value that matches the size.
+ * @param styleManager The instance of StyleManager
+ * @return A List of Broken Image Url
+ */
+DALI_TOOLKIT_API std::vector<std::string> GetBrokenImageUrlList(StyleManager styleManager);
+
+/**
+ * @brief This signal is emitted when the URL of the broken image is set
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName(StyleManager styleManager)
+ * @endcode
+ * @param styleManager The instance of StyleManager
+ * @return The signal to connect to
+ */
+DALI_TOOLKIT_API BrokenImageChangedSignalType& BrokenImageChangedSignal(StyleManager styleManager);
+
 } // namespace DevelStyleManager
 
 } // namespace Toolkit
index 41d7126..e4733c1 100644 (file)
@@ -1388,7 +1388,8 @@ void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x
   }
 
   const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(pixelFormat);
-  if(bytesPerPixel == 0u || bytesPerPixel == 12u || bytesPerPixel == 24u)
+  // Ignore when pixelFormat is invalid or contain float
+  if(bytesPerPixel == 0u || bytesPerPixel == 6u || bytesPerPixel == 12u)
   {
     return;
   }
index ced845a..f9f4376 100644 (file)
@@ -467,6 +467,8 @@ const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessi
 const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityRole",              Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE,               Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityHighlightable",     Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE,      Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityAttributes",        Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES,         Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "dispatchKeyEvents",              Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS,               Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+
 // clang-format on
 
 Control::Impl::Impl(Control& controlImpl)
@@ -501,7 +503,8 @@ Control::Impl::Impl(Control& controlImpl)
   mIsKeyboardNavigationSupported(false),
   mIsKeyboardFocusGroup(false),
   mIsEmittingResourceReadySignal(false),
-  mNeedToEmitResourceReady(false)
+  mNeedToEmitResourceReady(false),
+  mDispatchKeyEvents(true)
 {
   Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter(
     [](Dali::Actor actor) -> Dali::Accessibility::Accessible* {
@@ -1362,6 +1365,16 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         }
         break;
       }
+
+      case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
+      {
+        bool dispatch;
+        if(value.Get(dispatch))
+        {
+          controlImpl.mImpl->mDispatchKeyEvents = dispatch;
+        }
+        break;
+      }
     }
   }
 }
@@ -1522,6 +1535,11 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
         value = controlImpl.mImpl->mAccessibilityAttributes;
         break;
       }
+      case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
+      {
+        value = controlImpl.mImpl->mDispatchKeyEvents;
+        break;
+      }
     }
   }
 
index 73b12e0..94da0fc 100644 (file)
@@ -551,6 +551,7 @@ public:
   bool             mIsKeyboardFocusGroup : 1;             ///< Stores whether the control is a focus group.
   bool             mIsEmittingResourceReadySignal : 1;    ///< True during ResourceReady().
   bool             mNeedToEmitResourceReady : 1;          ///< True if need to emit the resource ready signal again.
+  bool             mDispatchKeyEvents : 1;                ///< Whether the actor emits key event signals
 
   RegisteredVisualContainer mRemoveVisuals; ///< List of visuals that are being replaced by another visual once ready
 
diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp b/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp
new file mode 100644 (file)
index 0000000..64e31d6
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/gl-view/gl-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+Dali::Toolkit::GlView GlView::New(Dali::Toolkit::GlView::ColorFormat colorFormat)
+{
+  GlView*               impl   = new GlView(colorFormat);
+  Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl);
+  impl->Initialize();
+  return handle;
+}
+
+GlView::GlView(Dali::Toolkit::GlView::ColorFormat colorFormat)
+: Control(ControlBehaviour(ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS)),
+  mRenderThread(nullptr),
+  mNativeImageQueue(nullptr),
+  mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS),
+  mColorFormat(colorFormat),
+  mDepth(false),
+  mStencil(false),
+  mMSAA(0)
+{
+}
+
+GlView::~GlView()
+{
+  if(mRenderThread)
+  {
+    mRenderThread->Stop();
+    mRenderThread->Join();
+  }
+}
+
+void GlView::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+{
+  if(mRenderThread)
+  {
+    mRenderThread->RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback);
+  }
+}
+
+void GlView::SetResizeCallback(CallbackBase* resizeCallback)
+{
+  if(mRenderThread)
+  {
+    mRenderThread->SetResizeCallback(resizeCallback);
+  }
+}
+
+bool GlView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version)
+{
+  // Init Graphics
+  mDepth   = depth;
+  mStencil = stencil;
+  mMSAA    = msaa;
+
+  int rVersion;
+
+  if(version == Dali::Toolkit::GlView::GraphicsApiVersion::GLES_VERSION_2_0)
+  {
+    rVersion = 20;
+  }
+  else
+  {
+    rVersion = 30;
+  }
+
+  if(mRenderThread)
+  {
+    return mRenderThread->SetGraphicsConfig(depth, stencil, msaa, rVersion);
+  }
+
+  return false;
+}
+
+void GlView::SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode)
+{
+  mRenderingMode    = mode;
+  Renderer renderer = Self().GetRendererAt(0);
+
+  if(mRenderingMode == Dali::Toolkit::GlView::RenderingMode::ON_DEMAND)
+  {
+    renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
+
+    if(mRenderThread)
+    {
+      mRenderThread->SetOnDemandRenderMode(true);
+    }
+  }
+  else
+  {
+    renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
+
+    if(mRenderThread)
+    {
+      mRenderThread->SetOnDemandRenderMode(false);
+    }
+  }
+}
+
+Dali::Toolkit::GlView::RenderingMode GlView::GetRenderingMode() const
+{
+  return mRenderingMode;
+}
+
+void GlView::RenderOnce()
+{
+  if(mRenderThread)
+  {
+    mRenderThread->RenderOnce();
+  }
+}
+
+void GlView::OnInitialize()
+{
+  //Create NativeImageSourceQueue with the size of 1,1
+  mNativeImageQueue = Dali::NativeImageSourceQueue::New(1, 1, GetColorFormat(mColorFormat));
+
+  if(!mNativeImageQueue)
+  {
+    DALI_LOG_ERROR("NativeImageSourceQueue is NULL");
+    return;
+  }
+
+  AddRenderer();
+
+  Actor self = Self();
+
+  //Create a RenderThread
+  mRenderThread = std::unique_ptr<GlViewRenderThread>(new GlViewRenderThread(mNativeImageQueue));
+  if(!mRenderThread)
+  {
+    DALI_LOG_ERROR("Fail to create GlView Render Thread!!!!\n");
+    return;
+  }
+
+  //Adding VisibilityChange Signal.
+  Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &GlView::OnControlVisibilityChanged);
+}
+
+void GlView::OnSizeSet(const Vector3& targetSize)
+{
+  Control::OnSizeSet(targetSize);
+
+  if(mRenderThread)
+  {
+    if(mNativeImageQueue)
+    {
+      mRenderThread->AcquireSurface();
+      mNativeImageQueue->SetSize(static_cast<uint32_t>(targetSize.x), static_cast<uint32_t>(targetSize.y));
+      mRenderThread->SetSurfaceSize(Vector2(targetSize.x, targetSize.y));
+      mRenderThread->ReleaseSurface();
+    }
+  }
+}
+
+Shader GlView::CreateShader()
+{
+  std::string fragmentShader = std::string(SHADER_GL_VIEW_FRAG);
+
+  if(mNativeImageQueue)
+  {
+    mNativeImageQueue->ApplyNativeFragmentShader(fragmentShader);
+  }
+
+  return Shader::New(SHADER_GL_VIEW_VERT, fragmentShader);
+}
+
+void GlView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
+{
+  Actor self = Self();
+  if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+  {
+    if(mRenderThread)
+    {
+      if(visible && DevelWindow::Get(self).IsVisible())
+      {
+        mRenderThread->Resume();
+      }
+      else
+      {
+        mRenderThread->Pause();
+      }
+    }
+  }
+}
+
+void GlView::OnWindowVisibilityChanged(Window window, bool visible)
+{
+  if(mRenderThread)
+  {
+    if(visible && Self().GetProperty<bool>(Actor::Property::VISIBLE))
+    {
+      mRenderThread->Resume();
+    }
+    else
+    {
+      mRenderThread->Pause();
+    }
+  }
+}
+
+void GlView::OnSceneConnection(int depth)
+{
+  Control::OnSceneConnection(depth);
+
+  Actor  self   = Self();
+  Window window = DevelWindow::Get(self);
+
+  if(window)
+  {
+    DevelWindow::VisibilityChangedSignal(window).Connect(this, &GlView::OnWindowVisibilityChanged);
+  }
+
+  if(mRenderThread)
+  {
+    if(self.GetProperty<bool>(Actor::Property::VISIBLE) && window.IsVisible())
+    {
+      mRenderThread->Resume();
+    }
+  }
+}
+
+void GlView::OnSceneDisconnection()
+{
+  Control::OnSceneDisconnection();
+  if(mRenderThread)
+  {
+    mRenderThread->Pause();
+  }
+}
+
+Dali::Geometry GlView::CreateTexturedQuad()
+{
+  struct Vertex
+  {
+    Dali::Vector2 position;
+  };
+
+  static const Vertex data[] = {{Dali::Vector2(-0.5f, -0.5f)},
+                                {Dali::Vector2(0.5f, -0.5f)},
+                                {Dali::Vector2(-0.5f, 0.5f)},
+                                {Dali::Vector2(0.5f, 0.5f)}};
+
+  uint32_t numberOfVertices = sizeof(data) / sizeof(Vertex);
+
+  Dali::VertexBuffer  vertexBuffer;
+  Dali::Property::Map vertexFormat;
+  vertexFormat["aPosition"] = Dali::Property::VECTOR2;
+
+  //Create a vertex buffer for vertex positions and texture coordinates
+  vertexBuffer = Dali::VertexBuffer::New(vertexFormat);
+  vertexBuffer.SetData(data, numberOfVertices);
+
+  //Create the geometry
+  Dali::Geometry geometry = Dali::Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  geometry.SetType(Dali::Geometry::TRIANGLE_STRIP);
+
+  return geometry;
+}
+
+void GlView::AddRenderer()
+{
+  if(!mNativeImageQueue)
+  {
+    DALI_LOG_ERROR("Target Surface is NULL");
+    return;
+  }
+
+  Actor    self     = Self();
+  Geometry geometry = CreateTexturedQuad();
+  Shader   shader   = CreateShader();
+  Renderer renderer = Renderer::New(geometry, shader);
+
+  Texture    nativeTexture = Texture::New(*mNativeImageQueue);
+  TextureSet textureSet    = TextureSet::New();
+  textureSet.SetTexture(0u, nativeTexture);
+
+  renderer.SetTextures(textureSet);
+
+  self.AddRenderer(renderer);
+}
+
+Dali::NativeImageSourceQueue::ColorFormat GlView::GetColorFormat(Dali::Toolkit::GlView::ColorFormat format)
+{
+  switch(format)
+  {
+    case Toolkit::GlView::ColorFormat::RGBA8888:
+    {
+      return Dali::NativeImageSourceQueue::ColorFormat::RGBA8888;
+    }
+
+    case Toolkit::GlView::ColorFormat::RGB888:
+    default:
+    {
+      return Dali::NativeImageSourceQueue::ColorFormat::RGBX8888;
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-impl.h b/dali-toolkit/internal/controls/gl-view/gl-view-impl.h
new file mode 100644 (file)
index 0000000..c0114ca
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GL_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_GL_VIEW_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+class GlView;
+
+namespace Internal
+{
+class GlView : public Dali::Toolkit::Internal::Control
+{
+protected:
+  virtual ~GlView();
+
+public:
+  /**
+   * @copydoc Dali::Toolkit::GlView::New()
+   */
+  static Dali::Toolkit::GlView New(Dali::Toolkit::GlView::ColorFormat colorFormat);
+
+  /**
+   * Construct a new GlView.
+   */
+  GlView(Dali::Toolkit::GlView::ColorFormat colorFormat);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::RegisterGlCallback()
+   */
+  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::SetResizeCallback()
+   */
+  void SetResizeCallback(CallbackBase* resizeCallback);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::SetGraphisConfig()
+   */
+  bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::SetRenderingMode()
+   */
+  void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::GetRenderingMode()
+   */
+  Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const;
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::RenderOnce()
+   */
+  void RenderOnce();
+
+private: // From Control
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize() override;
+
+  /**
+   * @copydoc Toolkit::Control::OnSceneConnection()
+   */
+  void OnSceneConnection(int depth) override;
+
+  /**
+   * @copydoc Toolkit::Control::OnSceneDisconnection()
+   */
+  void OnSceneDisconnection() override;
+
+  /**
+   * @copydoc Toolkit::Control::OnSizeSet()
+   */
+  void OnSizeSet(const Vector3& targetSize) override;
+
+private:
+  // Undefined copy constructor and assignment operators
+  GlView(const GlView& GlView);
+  GlView& operator=(const GlView& GlView);
+
+  /**
+   * Callback when the visibility of the GlView is changed
+   */
+  void OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type);
+
+  /**
+   * Callback when the visibility of the window is changed
+   */
+  void OnWindowVisibilityChanged(Dali::Window window, bool visible);
+
+  /**
+   * Creates the geometry for texturing.
+   */
+  Dali::Geometry CreateTexturedQuad();
+
+  /**
+   * Adds renderer to Actor.
+   */
+  void AddRenderer();
+
+  /**
+   * Creates shader for rendering.
+   */
+  Dali::Shader CreateShader();
+
+  /**
+   * @brief Gets the NativeImageSourceQueue's ColorFormat with the GlView's ColorFormat.
+   * @param[in] colorFormat the color format of the GlView.
+   * @return The color format of NativeImageSourceQueue
+   */
+  Dali::NativeImageSourceQueue::ColorFormat GetColorFormat(Dali::Toolkit::GlView::ColorFormat format);
+
+private:
+  std::unique_ptr<GlViewRenderThread>  mRenderThread;
+  Dali::NativeImageSourceQueuePtr      mNativeImageQueue;
+  Dali::Toolkit::GlView::RenderingMode mRenderingMode;
+  Dali::Toolkit::GlView::ColorFormat   mColorFormat;
+
+  bool mDepth;
+  bool mStencil;
+  int  mMSAA;
+};
+
+} // namespace Internal
+
+inline Dali::Toolkit::Internal::GlView& GetImpl(Dali::Toolkit::GlView& handle)
+{
+  DALI_ASSERT_ALWAYS(handle);
+  Dali::RefObject& impl = handle.GetImplementation();
+  return static_cast<Dali::Toolkit::Internal::GlView&>(impl);
+}
+
+inline const Dali::Toolkit::Internal::GlView& GetImpl(const Dali::Toolkit::GlView& handle)
+{
+  DALI_ASSERT_ALWAYS(handle);
+  const Dali::RefObject& impl = handle.GetImplementation();
+  return static_cast<const Dali::Toolkit::Internal::GlView&>(impl);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_GL_VIEW_H
diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp b/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp
new file mode 100644 (file)
index 0000000..db2e98c
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h>
+
+//EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+#include <chrono>
+#include <thread>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+constexpr unsigned int NANOSECONDS_PER_SECOND(1e+9);
+
+// The following values will get calculated at compile time
+constexpr float    DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
+constexpr uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
+
+} // namespace
+
+GlViewRenderThread::GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue)
+: mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mSurfaceSize(1, 1),
+  mNativeImageSurface(),
+  mNativeImageQueue(queue),
+  mSurfaceSemaphore(1),
+  mGlInitCallback(nullptr),
+  mGlRenderFrameCallback(nullptr),
+  mGlTerminateCallback(nullptr),
+  mResizeCallback(nullptr),
+  mDepth(false),
+  mStencil(false),
+  mMSAA(0),
+  mGraphicsApiVersion(20),
+  mConditionalWait(),
+  mIsThreadStarted(0),
+  mIsThreadStopped(0),
+  mIsThreadPaused(0),
+  mIsRenderRequested(0),
+  mRenderingMode(0),
+  mIsSurfaceResized(0),
+  mDefaultFrameDurationNanoseconds(DEFAULT_FRAME_DURATION_IN_NANOSECONDS)
+{
+  mNativeImageSurface = Dali::NativeImageSurface::New(mNativeImageQueue);
+
+  if(!mNativeImageSurface)
+  {
+    DALI_LOG_ERROR("Creating NativeImageSurface Failed, Could not start GlView Render Thread");
+  }
+}
+
+void GlViewRenderThread::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+{
+  if(!mGlInitCallback && !mGlRenderFrameCallback && !mGlTerminateCallback)
+  {
+    mGlInitCallback        = std::unique_ptr<CallbackBase>(initCallback);
+    mGlRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
+    mGlTerminateCallback   = std::unique_ptr<CallbackBase>(terminateCallback);
+  }
+}
+
+void GlViewRenderThread::SetResizeCallback(CallbackBase* resizeCallback)
+{
+  if(!mResizeCallback)
+  {
+    mResizeCallback = std::unique_ptr<CallbackBase>(resizeCallback);
+  }
+}
+
+bool GlViewRenderThread::SetGraphicsConfig(bool depth, bool stencil, int msaa, int version)
+{
+  mDepth              = depth;
+  mStencil            = stencil;
+  mMSAA               = msaa;
+  mGraphicsApiVersion = version;
+
+  if(mNativeImageSurface)
+  {
+    return mNativeImageSurface->SetGraphicsConfig(mDepth, mStencil, mMSAA, mGraphicsApiVersion);
+  }
+
+  return false;
+}
+
+void GlViewRenderThread::SetOnDemandRenderMode(bool onDemand)
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+  mRenderingMode = static_cast<unsigned int>(onDemand);
+  DALI_LOG_RELEASE_INFO("GlViewRenderThread::SetOnDemandRenderMode(): mRenderingMode: %d\n", mRenderingMode);
+  if(!onDemand && !mIsThreadPaused)
+  {
+    mConditionalWait.Notify(lock);
+  }
+}
+
+void GlViewRenderThread::SetSurfaceSize(Dali::Vector2 size)
+{
+  //GlViewRenderThread::Run was already blocked in Internal::GlView::OnSizeSet
+  mSurfaceSize      = size;
+  mIsSurfaceResized = 1;
+}
+
+void GlViewRenderThread::RenderOnce()
+{
+  //Notify GLRender thread.
+  Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
+  mIsRenderRequested = 1;
+  mConditionalWait.Notify(lock);
+}
+
+void GlViewRenderThread::GetNanoSeconds(uint64_t& timeInNanoseconds)
+{
+  // Get the time of a monotonic clock since its epoch.
+  auto epoch        = std::chrono::steady_clock::now().time_since_epoch();
+  auto duration     = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
+  timeInNanoseconds = static_cast<uint64_t>(duration.count());
+}
+
+void GlViewRenderThread::SleepUntil(uint64_t timeInNanoseconds)
+{
+  using Clock     = std::chrono::steady_clock;
+  using TimePoint = std::chrono::time_point<Clock>;
+
+  const Clock::duration duration = std::chrono::nanoseconds(timeInNanoseconds);
+  const TimePoint       timePoint(duration);
+
+  std::this_thread::sleep_until(timePoint);
+}
+
+void GlViewRenderThread::Run()
+{
+  Dali::SetThreadName("GlViewRenderer");
+  mLogFactory.InstallLogFunction();
+
+  int renderFrameResult = 0;
+
+  if(!mNativeImageSurface)
+  {
+    DALI_LOG_ERROR("NativeImageSurface is null, Could not start GlView Render Thread");
+    return;
+  }
+
+  AcquireSurface();
+  mNativeImageSurface->InitializeGraphics();
+  ReleaseSurface();
+
+  mNativeImageSurface->PreRender();
+  if(mGlInitCallback)
+  {
+    CallbackBase::Execute(*mGlInitCallback);
+  }
+
+  uint64_t timeToSleepUntil = 0;
+
+  while(RenderReady(timeToSleepUntil))
+  {
+    uint64_t currentFrameStartTime = 0;
+    GetNanoSeconds(currentFrameStartTime);
+
+    AcquireSurface();
+    mNativeImageSurface->PreRender();
+    if(mIsSurfaceResized)
+    {
+      if(mResizeCallback)
+      {
+        CallbackBase::Execute(*mResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
+      }
+      mIsSurfaceResized = 0;
+    }
+
+    if(mNativeImageSurface->CanRender())
+    {
+      if(mGlRenderFrameCallback)
+      {
+        renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGlRenderFrameCallback);
+        if(renderFrameResult)
+        {
+          mNativeImageSurface->PostRender();
+        }
+      }
+    }
+
+    ReleaseSurface();
+
+    if(timeToSleepUntil == 0)
+    {
+      timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
+    }
+    else
+    {
+      timeToSleepUntil += mDefaultFrameDurationNanoseconds;
+      uint64_t currentFrameEndTime = 0;
+      GetNanoSeconds(currentFrameEndTime);
+      while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
+      {
+        timeToSleepUntil += mDefaultFrameDurationNanoseconds;
+      }
+    }
+
+    SleepUntil(timeToSleepUntil);
+  }
+
+  if(mGlTerminateCallback)
+  {
+    CallbackBase::Execute(*mGlTerminateCallback);
+  }
+
+  mNativeImageSurface->TerminateGraphics();
+
+  return;
+}
+
+void GlViewRenderThread::Stop()
+{
+  // Set to come out Render Thread out of waiting condition.
+  Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
+  mIsThreadStopped = 1;
+  mIsThreadPaused  = 0;
+  mConditionalWait.Notify(lock);
+}
+
+void GlViewRenderThread::Pause()
+{
+  //Notify GLRender thread, If actor visibility is change
+  Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
+  mIsThreadPaused = 1;
+  mConditionalWait.Notify(lock);
+}
+
+void GlViewRenderThread::Resume()
+{
+  Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
+  if(!mIsThreadStarted)
+  {
+    Start();
+    mIsThreadStarted = 1;
+  }
+  mIsThreadPaused = 0;
+  mConditionalWait.Notify(lock);
+}
+
+bool GlViewRenderThread::RenderReady(uint64_t& timeToSleepUntil)
+{
+  ConditionalWait::ScopedLock lock(mConditionalWait);
+  while((!mIsThreadStopped && mRenderingMode && !mIsRenderRequested) || mIsThreadPaused)
+  {
+    timeToSleepUntil = 0;
+    mConditionalWait.Wait(lock);
+  }
+
+  mIsRenderRequested = 0;
+  // Keep the update-render thread alive if this thread is NOT to be destroyed
+  return !mIsThreadStopped;
+}
+
+void GlViewRenderThread::AcquireSurface()
+{
+  mSurfaceSemaphore.Acquire();
+}
+
+void GlViewRenderThread::ReleaseSurface()
+{
+  mSurfaceSemaphore.Release(1);
+}
+
+GlViewRenderThread::~GlViewRenderThread()
+{
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h b/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h
new file mode 100644 (file)
index 0000000..c27c832
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GL_VIEW_THREAD_H
+#define DALI_TOOLKIT_INTERNAL_GL_VIEW_THREAD_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/semaphore.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/integration-api/adaptor-framework/native-image-surface.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+ * @brief GlViewRenderThread is a render thread for GlView.
+ * This invokes user's callbacks.
+ */
+class GlViewRenderThread : public Dali::Thread
+{
+public:
+  /**
+   * Constructor
+   *
+   * @param[in] queue The NativeImageSourceQueue that GL renders onto
+   */
+  GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue);
+
+  /**
+   * destructor.
+   */
+  virtual ~GlViewRenderThread();
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::RegisterGlCallback()
+   */
+  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::SetResizeCallback()
+   */
+  void SetResizeCallback(CallbackBase* resizeCallback);
+
+  /**
+   * @copydoc Dali::Toolkit::GlView::SetGraphicsConfig()
+   */
+  bool SetGraphicsConfig(bool depth, bool stencil, int msaa, int version);
+
+  /**
+   * Enable OnDemand Rendering Mode
+   *
+   * @param[in] onDemand the flag of OnDemand Rendering Mode. If the flag is true, the rendering mode is set OnDemand,
+   * otherwise the flag is false, rendering mode is set continuous mode.
+   */
+  void SetOnDemandRenderMode(bool onDemand);
+
+  /**
+   * Sets the surface size
+   *
+   * @param[in] size the size of the NaitveImageSurface
+   */
+  void SetSurfaceSize(Dali::Vector2 size);
+
+  /**
+   * @copydoc Dali::Toolkit::RenderOnce()
+   */
+  void RenderOnce();
+
+  /**
+   * Pauses the render thread.
+   */
+  void Pause();
+
+  /**
+   * Resumes the render thread.
+   */
+  void Resume();
+
+  /**
+   * Stops the render thread.
+   * @note Should only be called in Stop as calling this will kill the render thread.
+   */
+  void Stop();
+
+  /**
+   * Acquires the surface resource
+   */
+  void AcquireSurface();
+
+  /**
+   * Releases the surface resource
+   */
+  void ReleaseSurface();
+
+protected:
+  /**
+   * The routine that the thread will execute once it is started.
+   */
+  void Run() override;
+
+private:
+  GlViewRenderThread(const GlViewRenderThread& obj) = delete;
+  GlViewRenderThread operator=(const GlViewRenderThread& obj) = delete;
+
+  /**
+   * Called by the Render Thread which ensures a wait if required.
+   *
+   * @param[out] timeToSleepUntil  The time remaining in nanoseconds to keep the thread sleeping before resuming.
+   * @return false, if the thread should stop.
+   */
+  bool RenderReady(uint64_t& timeToSleepUntil);
+
+  /**
+   * @brief Get the monotonic time since the clock's epoch.
+   * @param[out]  timeInNanoseconds  The time in nanoseconds since the reference point.
+   */
+  void GetNanoSeconds(uint64_t& timeInNanoseconds);
+
+  /**
+   * Blocks the execution of the current thread until specified sleep_time
+   * @param[in] timeInNanoseconds  The time blocking for
+   */
+  void SleepUntil(uint64_t timeInNanoseconds);
+
+private:
+  const Dali::LogFactoryInterface& mLogFactory;
+  Dali::Vector2                    mSurfaceSize; ///< The size of mNativeImageQueue
+  Dali::NativeImageSurfacePtr      mNativeImageSurface;
+  Dali::NativeImageSourceQueuePtr  mNativeImageQueue;
+  Semaphore<>                      mSurfaceSemaphore; ///< The semaphore to avoid race condition to the render target
+
+  std::unique_ptr<CallbackBase> mGlInitCallback;
+  std::unique_ptr<CallbackBase> mGlRenderFrameCallback;
+  std::unique_ptr<CallbackBase> mGlTerminateCallback;
+  std::unique_ptr<CallbackBase> mResizeCallback;
+
+  bool mDepth : 1;
+  bool mStencil : 1;
+  int  mMSAA;
+  int  mGraphicsApiVersion;
+
+  Dali::ConditionalWait mConditionalWait;
+  volatile unsigned int mIsThreadStarted;   ///< Whether this thread has been started.
+  volatile unsigned int mIsThreadStopped;   ///< Stop render thread. It means this render thread will be destroyed.
+  volatile unsigned int mIsThreadPaused;    ///< Sleep render thread by pause.
+  volatile unsigned int mIsRenderRequested; ///< Request rendering once
+  volatile unsigned int mRenderingMode;     ///< Rendering Mode, 0: Continuous, 1:OnDemand
+  volatile unsigned int mIsSurfaceResized;  ///< Invoke ResizeCallback when NativeImageSurface is resized.
+
+  uint64_t mDefaultFrameDurationNanoseconds; ///< Default duration of a frame (used for sleeping if not enough time elapsed). Not protected by lock, but written to rarely so not worth adding a lock when reading.
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_GL_SURFACE_VIEW_THREAD_H
index 77b29ca..85b2fe1 100755 (executable)
 #include <dali-toolkit/devel-api/controls/web-view/web-context.h>
 #include <dali-toolkit/devel-api/controls/web-view/web-cookie-manager.h>
 #include <dali-toolkit/devel-api/controls/web-view/web-settings.h>
-#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
 #include <dali-toolkit/public-api/image-loader/image.h>
-#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/public-api/image-loader/image-url.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 
 namespace Dali
 {
@@ -634,7 +633,7 @@ Dali::Toolkit::ImageView WebView::CreateImageView(Dali::PixelData pixel) const
     return Dali::Toolkit::ImageView();
   }
 
-  Dali::Toolkit::ImageUrl url       = Dali::Toolkit::Image::GenerateUrl(pixel);
+  Dali::Toolkit::ImageUrl  url       = Dali::Toolkit::Image::GenerateUrl(pixel);
   Dali::Toolkit::ImageView imageView = Dali::Toolkit::ImageView::New(url.GetUrl());
   imageView.SetProperty(Dali::Actor::Property::SIZE, Vector2(pixel.GetWidth(), pixel.GetHeight()));
   return imageView;
@@ -777,9 +776,8 @@ void WebView::OnInitialFrameRendered()
 {
   mWebEngine.FrameRenderedSignal().Disconnect(this, &WebView::OnInitialFrameRendered);
 
-  Texture           texture        = Dali::Texture::New(*mWebEngine.GetNativeImageSource());
-  const std::string nativeImageUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
-  mVisual                          = Toolkit::VisualFactory::Get().CreateVisual({{Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE}, {Toolkit::ImageVisual::Property::URL, nativeImageUrl}});
+  Dali::Toolkit::ImageUrl nativeImageUrl = Dali::Toolkit::Image::GenerateUrl(mWebEngine.GetNativeImageSource());
+  mVisual                                = Toolkit::VisualFactory::Get().CreateVisual({{Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE}, {Toolkit::ImageVisual::Property::URL, nativeImageUrl.GetUrl()}});
 
   if(mVisual)
   {
index 7f02340..f1aa866 100644 (file)
@@ -109,6 +109,8 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/controls/video-view/video-view-impl.cpp
    ${toolkit_src_dir}/controls/web-view/web-view-impl.cpp
    ${toolkit_src_dir}/controls/camera-view/camera-view-impl.cpp
+   ${toolkit_src_dir}/controls/gl-view/gl-view-impl.cpp
+   ${toolkit_src_dir}/controls/gl-view/gl-view-render-thread.cpp
    ${toolkit_src_dir}/accessibility-manager/accessibility-manager-impl.cpp
 
    ${toolkit_src_dir}/feedback/feedback-style.cpp
index ad87ac3..ebdb214 100644 (file)
@@ -26,6 +26,9 @@
 #include <dali/public-api/actors/layer.h>
 #include <cstring> // for strcmp
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -130,6 +133,18 @@ bool KeyInputFocusManager::OnKeyEvent(const KeyEvent& event)
   Toolkit::Control control = GetCurrentFocusControl();
   if(control)
   {
+    Dali::Actor dispatch = control;
+    while(dispatch)
+    {
+      // If the DISPATCH_KEY_EVENTS is false, it cannot emit key event.
+      Toolkit::Control dispatchControl = Toolkit::Control::DownCast(dispatch);
+      if(dispatchControl && !dispatchControl.GetProperty<bool>(Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS))
+      {
+        return true;
+      }
+      dispatch = dispatch.GetParent();
+    }
+
     // Notify the control about the key event
     consumed = EmitKeyEventSignal(control, event);
   }
index 74e8f58..13be4df 100644 (file)
@@ -23,6 +23,7 @@ uniform lowp vec3 mixColor;
 uniform mediump float borderlineWidth;
 uniform mediump float borderlineOffset;
 uniform lowp vec4 borderlineColor;
+uniform lowp vec4 uActorColor;
 #endif
 #if IS_REQUIRED_BLUR
 uniform mediump float blurRadius;
@@ -121,28 +122,54 @@ lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
   {
     // potential is inside borderline range.
     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+
+    // Muliply borderlineWidth to resolve very thin borderline
+    borderlineOpacity *= min(1.0, borderlineWidth);
   }
 
-  //calculate inside of borderline when outilneColor.a < 1.0
-  if(borderlineColor.a < 1.0)
+  lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
+  lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
+  // NOTE : color-visual is always not preMultiplied.
+
+  // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
+  // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
+  // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
+  if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 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);
+      // potential is out of texture range.
+      textureColor = vec4(0.0);
     }
-    else if(potential > MinTexturelinePotential)
+    else
     {
-      // potential is in texture range
-      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      // potential is in texture range.
+      lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      textureColor.a *= textureAlphaScale;
+      textureColor.rgb *= textureColor.a;
     }
-    borderlineOpacity *= borderlineColor.a;
-    return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+
+    // NOTE : color-visual is always not preMultiplied.
+    borderlineColorAlpha *= borderlineOpacity;
+    borderlineColorRGB *= borderlineColorAlpha;
+    // We use pre-multiplied color to reduce operations.
+    // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
+
+    // Manual blend operation with premultiplied colors.
+    // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
+    // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
+    // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
+    // Else, return vec4((rgb*alpha) / alpha, alpha)
+
+    lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
+    lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
+    // TODO : Need to find some way without division
+    return vec4(finalMultipliedRGB / finalAlpha, finalAlpha);
   }
-  return mix(textureColor, borderlineColor, borderlineOpacity);
+  return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
 }
 #endif
 
@@ -239,13 +266,13 @@ mediump float calculateBlurOpacity()
 
 void main()
 {
-  lowp vec4 targetColor = vec4(mixColor, 1.0);
+  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 * uColor;
+    OUT_COLOR = targetColor;
     return;
   }
   PreprocessPotential();
@@ -254,7 +281,7 @@ void main()
 #if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
   targetColor = convertBorderlineColor(targetColor);
 #endif
-  OUT_COLOR = targetColor * uColor;
+  OUT_COLOR = targetColor;
 
 #if IS_REQUIRED_BLUR
   mediump float opacity = calculateBlurOpacity();
diff --git a/dali-toolkit/internal/graphics/shaders/gl-view.frag b/dali-toolkit/internal/graphics/shaders/gl-view.frag
new file mode 100644 (file)
index 0000000..9b0b917
--- /dev/null
@@ -0,0 +1,8 @@
+uniform lowp vec4          uColor;
+varying mediump vec2       vTexCoord;
+uniform samplerExternalOES sTexture;
+
+void main()
+{
+  gl_FragColor = texture2D(sTexture, vTexCoord) * uColor;
+}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/gl-view.vert b/dali-toolkit/internal/graphics/shaders/gl-view.vert
new file mode 100644 (file)
index 0000000..eeec383
--- /dev/null
@@ -0,0 +1,11 @@
+attribute mediump vec2 aPosition;
+uniform mediump mat4   uMvpMatrix;
+uniform mediump vec3   uSize;
+varying mediump vec2   vTexCoord;
+
+void main()
+{
+  vec4 position = vec4(aPosition, 0.0, 1.0) * vec4(uSize, 1.0);
+  vTexCoord     = aPosition + vec2(0.5);
+  gl_Position   = uMvpMatrix * position;
+}
\ No newline at end of file
index cb72c67..80090f8 100644 (file)
@@ -25,6 +25,7 @@ uniform lowp vec3 mixColor;
 uniform mediump float borderlineWidth;
 uniform mediump float borderlineOffset;
 uniform lowp vec4 borderlineColor;
+uniform lowp vec4 uActorColor;
 #endif
 
 #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
@@ -120,29 +121,54 @@ lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
   {
     // potential is inside borderline range.
     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+
+    // Muliply borderlineWidth to resolve very thin borderline
+    borderlineOpacity *= min(1.0, borderlineWidth);
   }
 
-  //calculate inside of borderline when outilneColor.a < 1.0
-  if(borderlineColor.a < 1.0)
+  lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
+  lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
+  // NOTE : gradient-visual is always preMultiplied.
+  borderlineColorRGB *= borderlineColorAlpha;
+
+  // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
+  // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
+  // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
+  if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
   {
     mediump float tCornerRadius = -gCenterPosition;
     mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
     mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
-    lowp vec3 BorderlineColorRGB = borderlineColor.xyz * borderlineColor.a;
     if(potential > MaxTexturelinePotential)
     {
-      // potential is out of texture range. use borderline color instead of texture
-      textureColor = vec4(BorderlineColorRGB, 0.0);
+      // potential is out of texture range.
+      textureColor = vec4(0.0);
     }
-    else if(potential > MinTexturelinePotential)
+    else
     {
-      // potential is in texture range
-      textureColor = mix(textureColor, vec4(BorderlineColorRGB, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      // potential is in texture range.
+      lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      textureColor.a *= textureAlphaScale;
+      textureColor.rgb *= textureAlphaScale;
     }
-    borderlineOpacity *= borderlineColor.a;
-    return mix(textureColor, vec4(BorderlineColorRGB, 1.0), borderlineOpacity);
+
+    // NOTE : gradient-visual is always preMultiplied.
+    borderlineColorAlpha *= borderlineOpacity;
+    borderlineColorRGB *= borderlineOpacity;
+    // We use pre-multiplied color to reduce operations.
+    // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
+
+    // Manual blend operation with premultiplied colors.
+    // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
+    // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
+    // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
+    // Else, return vec4((rgb*alpha) / alpha, alpha)
+
+    lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
+    lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
+    return vec4(finalMultipliedRGB, finalAlpha);
   }
-  return mix(textureColor, borderlineColor, borderlineOpacity);
+  return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
 }
 #endif
 
@@ -171,16 +197,16 @@ mediump float calculateCornerOpacity()
 void main()
 {
 #if RADIAL
-  lowp vec4 textureColor = TEXTURE(sTexture, vec2(length(vTexCoord), 0.5)) * vec4(mixColor, 1.0);
+  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);
+  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 * uColor;
+    OUT_COLOR = textureColor;
     return;
   }
   PreprocessPotential();
@@ -189,7 +215,7 @@ void main()
 #if IS_REQUIRED_BORDERLINE
   textureColor = convertBorderlineColor(textureColor);
 #endif
-  OUT_COLOR = textureColor * uColor;
+  OUT_COLOR = textureColor;
 
 #if IS_REQUIRED_ROUNDED_CORNER
   mediump float opacity = calculateCornerOpacity();
index f9e80fe..edaf643 100644 (file)
@@ -61,8 +61,10 @@ vec4 ComputeVertexPosition()
   vOptRectSize -= 0.2929 * maxRadius + 1.0;
 #endif
 
+  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
 #if IS_REQUIRED_BORDERLINE
   vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+  vertexPosition.xy *= (1.0 + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth / visualSize);
   vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
 #elif IS_REQUIRED_ROUNDED_CORNER
   vPosition = aPosition * visualSize;
@@ -70,15 +72,16 @@ vec4 ComputeVertexPosition()
   mediump vec2 vPosition = aPosition * visualSize;
 #endif
 
+#if USER_SPACE
+  vertexPosition.xyz *= uSize;
+#endif
+
+  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
+
   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;
 }
index 0bba311..37f080f 100644 (file)
@@ -36,6 +36,7 @@ uniform lowp float preMultipliedAlpha;
 uniform mediump float borderlineWidth;
 uniform mediump float borderlineOffset;
 uniform lowp vec4 borderlineColor;
+uniform lowp vec4 uActorColor;
 #endif
 
 #if ATLAS_CUSTOM_WARP
@@ -142,30 +143,53 @@ lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
   {
     // potential is inside borderline range.
     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+
+    // Muliply borderlineWidth to resolve very thin borderline
+    borderlineOpacity *= min(1.0, borderlineWidth);
   }
 
-  //calculate inside of borderline when outilneColor.a < 1.0
-  if(borderlineColor.a < 1.0)
+  lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
+  lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
+  borderlineColorRGB *= mix(1.0, borderlineColorAlpha, preMultipliedAlpha);
+
+  // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
+  // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
+  // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
+  if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
   {
     mediump float tCornerRadius = -gCenterPosition;
     mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
     mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
-    lowp vec3 BorderlineColorRGB = borderlineColor.xyz;
-    BorderlineColorRGB *= mix(1.0, borderlineColor.a, preMultipliedAlpha);
     if(potential > MaxTexturelinePotential)
     {
-      // potential is out of texture range. use borderline color instead of texture
-      textureColor = vec4(BorderlineColorRGB, 0.0);
+      // potential is out of texture range.
+      textureColor = vec4(0.0);
     }
-    else if(potential > MinTexturelinePotential)
+    else
     {
-      // potential is in texture range
-      textureColor = mix(textureColor, vec4(BorderlineColorRGB, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      // potential is in texture range.
+      lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+      textureColor.a *= textureAlphaScale;
+      textureColor.rgb *= mix(textureColor.a, textureAlphaScale, preMultipliedAlpha);
     }
-    borderlineOpacity *= borderlineColor.a;
-    return mix(textureColor, vec4(BorderlineColorRGB, 1.0), borderlineOpacity);
+
+    borderlineColorAlpha *= borderlineOpacity;
+    borderlineColorRGB *= mix(borderlineColorAlpha, borderlineOpacity, preMultipliedAlpha);
+    // We use pre-multiplied color to reduce operations.
+    // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
+
+    // Manual blend operation with premultiplied colors.
+    // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
+    // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
+    // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
+    // Else, return vec4((rgb*alpha) / alpha, alpha)
+
+    lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
+    lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
+    // TODO : Need to find some way without division
+    return vec4(finalMultipliedRGB * mix(1.0 / finalAlpha, 1.0, preMultipliedAlpha), finalAlpha);
   }
-  return mix(textureColor, borderlineColor, borderlineOpacity);
+  return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
 }
 #endif
 
@@ -202,13 +226,13 @@ void main()
   mediump vec2 texCoord = vTexCoord;
 #endif
 
-  lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 );
+  lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor;
 
 #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 * uColor;
+    OUT_COLOR = textureColor;
     return;
   }
   PreprocessPotential();
@@ -217,7 +241,7 @@ void main()
 #if IS_REQUIRED_BORDERLINE
   textureColor = convertBorderlineColor(textureColor);
 #endif
-  OUT_COLOR = textureColor * uColor;
+  OUT_COLOR = textureColor;
 
 #if IS_REQUIRED_ROUNDED_CORNER
   mediump float opacity = calculateCornerOpacity();
index 0968081..959724b 100644 (file)
@@ -45,6 +45,8 @@ const char* APPLICATION_RESOURCE_PATH_KEY = "APPLICATION_RESOURCE_PATH";
 
 const char* DEFAULT_TOOLKIT_PACKAGE_PATH = "/toolkit/";
 
+static constexpr int32_t COUNT_BROKEN_IMAGE_MAX = 3;
+
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_STYLE");
 #endif
@@ -125,6 +127,9 @@ StyleManager::StyleManager()
 
   // Sound & haptic style
   mFeedbackStyle = new FeedbackStyle();
+
+  // Initialize BrokenImages
+  mBrokenImageUrls.assign(COUNT_BROKEN_IMAGE_MAX, "");
 }
 
 StyleManager::~StyleManager()
@@ -230,6 +235,11 @@ Toolkit::StyleManager::StyleChangedSignalType& StyleManager::ControlStyleChangeS
   return mControlStyleChangeSignal;
 }
 
+Toolkit::DevelStyleManager::BrokenImageChangedSignalType& StyleManager::BrokenImageChangedSignal()
+{
+  return mBrokenImageChangedSignal;
+}
+
 void StyleManager::SetTheme(const std::string& themeFile)
 {
   bool themeLoaded = false;
@@ -309,6 +319,34 @@ const Property::Map StyleManager::GetConfigurations()
   return result;
 }
 
+void StyleManager::SetBrokenImageUrl(DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl)
+{
+  int brokenType = static_cast<int>(brokenImageType);
+  mBrokenImageUrls[brokenType] = brokenImageUrl;
+  Toolkit::StyleManager styleManager = StyleManager::Get();
+  mBrokenImageChangedSignal.Emit(styleManager);
+}
+
+std::string StyleManager::GetBrokenImageUrl(DevelStyleManager::BrokenImageType brokenImageType)
+{
+  int brokenType = static_cast<int>(brokenImageType);
+  return mBrokenImageUrls[brokenType];
+}
+
+std::vector<std::string> StyleManager::GetBrokenImageUrlList()
+{
+  // create a list for brokenImage
+  std::vector<std::string> brokenImageUrlList;
+  for(int i = 0; i < COUNT_BROKEN_IMAGE_MAX; i++)
+  {
+    if(!mBrokenImageUrls[i].empty())
+    {
+      brokenImageUrlList.push_back(mBrokenImageUrls[i]);
+    }
+  }
+  return brokenImageUrlList;
+}
+
 bool StyleManager::LoadFile(const std::string& filename, std::string& stringOut)
 {
   DALI_ASSERT_DEBUG(0 != filename.length());
index b6eaff5..56e61f0 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/devel-api/builder/builder.h>
 #include <dali-toolkit/internal/builder/style.h>
 #include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
 
 namespace Dali
 {
@@ -95,6 +96,21 @@ public: // Public API
   const Property::Map GetConfigurations();
 
   /**
+   * @copydoc Toolkit::DevelStyleManager::SetBrokenImageUrl
+   */
+  void SetBrokenImageUrl(DevelStyleManager::BrokenImageType brokenImageType, const std::string& brokenImageUrl);
+
+  /**
+   * @copydoc Toolkit::DevelStyleManager::GetBrokenImageUrl
+   */
+  std::string GetBrokenImageUrl(DevelStyleManager::BrokenImageType brokenImageType);
+
+  /**
+   * @copydoc Toolkit::DevelStyleManager::GetBrokenImageUrlList
+   */
+  std::vector<std::string> GetBrokenImageUrlList();
+
+  /**
    * @brief Apply the theme style to a control.
    *
    * @param[in] control The control to apply style.
@@ -136,6 +152,12 @@ public:
    */
   Toolkit::StyleManager::StyleChangedSignalType& ControlStyleChangeSignal();
 
+  /**
+   * This signal is sent to the visual factory following a broken image change.
+   * It should not be exposed in the public API
+   */
+  Toolkit::DevelStyleManager::BrokenImageChangedSignalType& BrokenImageChangedSignal();
+
 private:
   typedef std::vector<std::string> StringList;
 
@@ -233,9 +255,12 @@ private:
 
   Toolkit::Internal::FeedbackStyle* mFeedbackStyle; ///< Feedback style
 
+  std::vector<std::string> mBrokenImageUrls;    ///< Broken Image Urls received from user
+
   // Signals
-  Toolkit::StyleManager::StyleChangedSignalType mControlStyleChangeSignal; ///< Emitted when the style( theme/font ) changes for the controls to style themselves
-  Toolkit::StyleManager::StyleChangedSignalType mStyleChangedSignal;       ///< Emitted after the controls have been styled
+  Toolkit::StyleManager::StyleChangedSignalType            mControlStyleChangeSignal; ///< Emitted when the style( theme/font ) changes for the controls to style themselves
+  Toolkit::StyleManager::StyleChangedSignalType            mStyleChangedSignal;       ///< Emitted after the controls have been styled
+  Toolkit::DevelStyleManager::BrokenImageChangedSignalType mBrokenImageChangedSignal; ///< Emitted after brokenImageChangedSignal
 };
 
 } // namespace Internal
index da54e1e..9693cc8 100644 (file)
@@ -807,9 +807,14 @@ TextureSet AnimatedImageVisual::SetLoadingFailed()
   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::FAILED)\n");
   ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
 
-  TextureSet textureSet  = TextureSet::New();
-  Texture    brokenImage = mFactoryCache.GetBrokenVisualImage();
-  textureSet.SetTexture(0u, brokenImage);
+  Actor actor = mPlacementActor.GetHandle();
+  Vector2 imageSize = Vector2::ZERO;
+  if(actor)
+  {
+    imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+  }
+  mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+  TextureSet textureSet = mImpl->mRenderer.GetTextures();
 
   if(mFrameDelayTimer)
   {
index 35d7456..89d02e8 100644 (file)
@@ -305,14 +305,10 @@ void AnimatedVectorImageVisual::DoSetOnScene(Actor& actor)
 
   if(mLoadFailed)
   {
-    TextureSet textureSet = TextureSet::New();
-    mImpl->mRenderer.SetTextures(textureSet);
-
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-    textureSet.SetTexture(0u, brokenImage);
-
+    Vector2 imageSize = Vector2::ZERO;
+    imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
-
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
   }
   else
index 91bdc42..86a37ab 100644 (file)
@@ -528,10 +528,11 @@ VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool
   // is casted to use the default duration.
   mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
   auto current        = std::chrono::steady_clock::now();
+  mDroppedFrames      = 0;
+
   if(renderNow)
   {
     mNextFrameStartTime = current;
-    mDroppedFrames      = 0;
   }
   else if(mNextFrameStartTime < current)
   {
index 9863364..593eeb6 100644 (file)
@@ -72,7 +72,7 @@ ColorVisual::ColorVisual(VisualFactoryCache& factoryCache)
 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::COLOR),
   mBlurRadius(0.0f),
   mBlurRadiusIndex(Property::INVALID_INDEX),
-  mNeedBlurRadius(false)
+  mAlwaysUsingBlurRadius(false)
 {
 }
 
@@ -217,7 +217,7 @@ Shader ColorVisual::GenerateShader() const
 
   bool roundedCorner = IsRoundedCornerRequired();
   bool borderline    = IsBorderlineRequired();
-  bool blur          = !EqualsZero(mBlurRadius) || mNeedBlurRadius;
+  bool blur          = !EqualsZero(mBlurRadius) || mAlwaysUsingBlurRadius;
   int shaderTypeFlag = ColorVisualRequireFlag::DEFAULT;
 
   if(roundedCorner)
@@ -276,9 +276,10 @@ Dali::Property ColorVisual::OnGetPropertyObject(Dali::Property::Key key)
   {
     mBlurRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME, mBlurRadius);
 
-    mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+    // Blur is animated now. we always have to use blur feature.
+    mAlwaysUsingBlurRadius = true;
 
-    mNeedBlurRadius = true;
+    mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
 
     // Change shader
     UpdateShader();
index 1f2af5c..6ced771 100644 (file)
@@ -131,9 +131,9 @@ private:
   ColorVisual& operator=(const ColorVisual& colorRenderer);
 
 private:
-  float           mBlurRadius;      ///< The blur radius
-  Property::Index mBlurRadiusIndex; ///< The blur radius property index
-  bool            mNeedBlurRadius;  ///< Whether we need the blur radius in shader.
+  float           mBlurRadius;                ///< The blur radius
+  Property::Index mBlurRadiusIndex;           ///< The blur radius property index
+  bool            mAlwaysUsingBlurRadius : 1; ///< Whether we need the blur radius in shader always.
 };
 
 } // namespace Internal
index 0251a1d..7e404ca 100644 (file)
@@ -513,8 +513,14 @@ void ImageVisual::GetNaturalSize(Vector2& naturalSize)
       }
       else
       {
-        Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-
+        Actor actor = mPlacementActor.GetHandle();
+        Vector2 imageSize = Vector2::ZERO;
+        if(actor)
+        {
+          imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+        }
+        mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+        Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0);
         naturalSize.x = brokenImage.GetWidth();
         naturalSize.y = brokenImage.GetWidth();
       }
@@ -710,12 +716,12 @@ void ImageVisual::DoSetOnScene(Actor& actor)
   }
   else if(mLoadState == TextureManager::LoadState::LOAD_FAILED)
   {
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-
-    mTextures = TextureSet::New();
-    mTextures.SetTexture(0u, brokenImage);
-    mImpl->mRenderer.SetTextures(mTextures);
-
+    Vector2 imageSize = Vector2::ZERO;
+    if(actor)
+    {
+      imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    }
+    mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
     mPlacementActor.Reset();
 
@@ -860,26 +866,30 @@ void ImageVisual::UploadComplete(bool loadingSuccess, int32_t textureId, Texture
     EnablePreMultipliedAlpha(preMultiplied);
 
     Actor actor = mPlacementActor.GetHandle();
-    if(actor)
+    if(!loadingSuccess)
     {
-      actor.AddRenderer(mImpl->mRenderer);
-      // reset the weak handle so that the renderer only get added to actor once
-      mPlacementActor.Reset();
+      Vector2 imageSize = Vector2::ZERO;
+      if(actor)
+      {
+        imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+      }
+      mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+      textureSet = mImpl->mRenderer.GetTextures();
     }
-
-    if(!loadingSuccess)
+    else
     {
-      Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-
-      textureSet = TextureSet::New();
-      textureSet.SetTexture(0u, brokenImage);
+      Sampler sampler = Sampler::New();
+      sampler.SetWrapMode(mWrapModeU, mWrapModeV);
+      textureSet.SetSampler(0u, sampler);
       mImpl->mRenderer.SetTextures(textureSet);
     }
 
-    Sampler sampler = Sampler::New();
-    sampler.SetWrapMode(mWrapModeU, mWrapModeV);
-    textureSet.SetSampler(0u, sampler);
-    mImpl->mRenderer.SetTextures(textureSet);
+    if(actor)
+    {
+      actor.AddRenderer(mImpl->mRenderer);
+      // reset the weak handle so that the renderer only get added to actor once
+      mPlacementActor.Reset();
+    }
   }
 
   // Storing TextureSet needed when renderer staged.
index 5f8ddff..cb2850d 100644 (file)
@@ -104,7 +104,6 @@ std::size_t NPatchLoader::Load(TextureManager& textureManager, TextureUploadObse
             newData->AddObserver(textureObserver);
 
             mCache.PushBack(newData);
-
             return newData->GetId(); // valid ids start from 1u
           }
         }
@@ -133,7 +132,6 @@ std::size_t NPatchLoader::Load(TextureManager& textureManager, TextureUploadObse
     preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
     data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
   }
-
   return data->GetId();
 }
 
index d9c26aa..e87e244 100644 (file)
@@ -562,7 +562,14 @@ void NPatchVisual::ApplyTextureAndUniforms()
     DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str());
     textureSet = TextureSet::New();
 
-    Texture croppedImage = mFactoryCache.GetBrokenVisualImage();
+    Actor actor = mPlacementActor.GetHandle();
+    Vector2 imageSize = Vector2::ZERO;
+    if(actor)
+    {
+      imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    }
+    mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
+    Texture croppedImage = mImpl->mRenderer.GetTextures().GetTexture(0);
     textureSet.SetTexture(0u, croppedImage);
     mImpl->mRenderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
     mImpl->mRenderer.RegisterProperty("uFixed[1]", Vector2::ZERO);
index 67fd435..5d1fff1 100644 (file)
@@ -157,9 +157,9 @@ void SvgVisual::DoSetOnScene(Actor& actor)
 
   if(mLoadFailed)
   {
-    Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-    textureSet.SetTexture(0u, brokenImage);
-
+    Vector2 imageSize = Vector2::ZERO;
+    imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+    mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
     actor.AddRenderer(mImpl->mRenderer);
 
     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
@@ -327,11 +327,9 @@ void SvgVisual::ApplyRasterizedImage(VectorImageRenderer vectorRenderer, PixelDa
     Actor actor = mPlacementActor.GetHandle();
     if(actor)
     {
-      TextureSet textureSet = mImpl->mRenderer.GetTextures();
-
-      Texture brokenImage = mFactoryCache.GetBrokenVisualImage();
-      textureSet.SetTexture(0u, brokenImage);
-
+      Vector2 imageSize = Vector2::ZERO;
+      imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
+      mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
       actor.AddRenderer(mImpl->mRenderer);
     }
 
index 53b5246..8106899 100644 (file)
@@ -134,8 +134,8 @@ Internal::Visual::Base::Impl::Impl(FittingMode fittingMode, Toolkit::Visual::Typ
   mFlags(0),
   mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
   mType(type),
-  mNeedCornerRadius(false),
-  mNeedBorderline(false)
+  mAlwaysUsingBorderline(false),
+  mAlwaysUsingCornerRadius(false)
 {
 }
 
index 52e0d98..64ab52f 100644 (file)
@@ -134,12 +134,12 @@ struct Base::Impl
   Property::Index                 mBorderlineColorIndex;
   Property::Index                 mBorderlineOffsetIndex;
   Property::Index                 mCornerRadiusIndex;
-  FittingMode                     mFittingMode; //< How the contents should fit the view
+  FittingMode                     mFittingMode; ///< How the contents should fit the view
   int                             mFlags;
   Toolkit::Visual::ResourceStatus mResourceStatus;
   const Toolkit::Visual::Type     mType;
-  bool                            mNeedCornerRadius;
-  bool                            mNeedBorderline;
+  bool                            mAlwaysUsingBorderline : 1;   ///< Whether we need the borderline in shader always.
+  bool                            mAlwaysUsingCornerRadius : 1; ///< Whether we need the corner radius in shader always.
 };
 
 } // namespace Visual
index 49b3120..443c51c 100644 (file)
@@ -60,6 +60,56 @@ DALI_ENUM_TO_STRING_TABLE_BEGIN(VISUAL_FITTING_MODE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Visual::FittingMode, FIT_HEIGHT)
 DALI_ENUM_TO_STRING_TABLE_END(VISUAL_FITTING_MODE)
 
+/**
+ * @brief Check whether this visual type can use corner radius feature or not.
+ * @param type VisualType that want to checkup
+ * @return true if type can use corner radius feature.
+ */
+static bool IsTypeAvailableForCornerRadius(Toolkit::Visual::Type type)
+{
+  switch(static_cast<Toolkit::DevelVisual::Type>(type))
+  {
+    case Toolkit::Visual::Type::COLOR:
+    case Toolkit::Visual::Type::GRADIENT:
+    case Toolkit::Visual::Type::IMAGE:
+    case Toolkit::Visual::Type::SVG:
+    case Toolkit::Visual::Type::ANIMATED_IMAGE:
+    case Toolkit::DevelVisual::Type::ANIMATED_VECTOR_IMAGE:
+    {
+      return true;
+    }
+    default:
+    {
+      return false;
+    }
+  }
+}
+
+/**
+ * @brief Check whether this visual type can use borderline feature or not.
+ * @param type VisualType that want to checkup
+ * @return true if type can use borderline feature.
+ */
+static bool IsTypeAvailableForBorderline(Toolkit::Visual::Type type)
+{
+  switch(static_cast<Toolkit::DevelVisual::Type>(type))
+  {
+    case Toolkit::Visual::Type::COLOR:
+    case Toolkit::Visual::Type::GRADIENT:
+    case Toolkit::Visual::Type::IMAGE:
+    case Toolkit::Visual::Type::SVG:
+    case Toolkit::Visual::Type::ANIMATED_IMAGE:
+    case Toolkit::DevelVisual::Type::ANIMATED_VECTOR_IMAGE:
+    {
+      return true;
+    }
+    default:
+    {
+      return false;
+    }
+  }
+}
+
 } // namespace
 
 Visual::Base::Base(VisualFactoryCache& factoryCache, FittingMode fittingMode, Toolkit::Visual::Type type)
@@ -95,7 +145,7 @@ void Visual::Base::Initialize()
       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);
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON_WITHOUT_CULL);
     }
   }
 }
@@ -525,22 +575,32 @@ bool Visual::Base::IsOnScene() const
 
 bool Visual::Base::IsRoundedCornerRequired() const
 {
-  if(mImpl->mRenderer && mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
+  // If VisualType doesn't support rounded corner, always return false.
+  if(IsTypeAvailableForCornerRadius(mImpl->mType))
   {
-    // Update values from Renderer
-    mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mCornerRadiusIndex);
+    if(mImpl->mRenderer && mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
+    {
+      // Update values from Renderer
+      mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mCornerRadiusIndex);
+    }
+    return !(mImpl->mCornerRadius == Vector4::ZERO) || mImpl->mAlwaysUsingCornerRadius;
   }
-  return !(mImpl->mCornerRadius == Vector4::ZERO) || mImpl->mNeedCornerRadius;
+  return false;
 }
 
 bool Visual::Base::IsBorderlineRequired() const
 {
-  if(mImpl->mRenderer && mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+  // If VisualType doesn't support borderline, always return false.
+  if(IsTypeAvailableForBorderline(mImpl->mType))
   {
-    // Update values from Renderer
-    mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+    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->mAlwaysUsingBorderline;
   }
-  return !EqualsZero(mImpl->mBorderlineWidth) || mImpl->mNeedBorderline;
+  return false;
 }
 
 void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
@@ -897,33 +957,42 @@ 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::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))
+    if(IsTypeAvailableForBorderline(mImpl->mType) &&
+       ((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);
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON_WITHOUT_CULL);
 
       // 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;
+
+      // Borderline is animated now. we always have to use borderline feature.
+      mImpl->mAlwaysUsingBorderline = 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))
+    else if(IsTypeAvailableForCornerRadius(mImpl->mType) && ((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);
       mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
 
-      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+      // ConerRadius is animated now. we always have to use corner radius feature.
+      mImpl->mAlwaysUsingCornerRadius = true;
+
+      if(!IsBorderlineRequired())
+      {
+        // If IsBorderlineRequired is true, BLEND_MODE is already BlendMode::ON_WITHOUT_CULL. So we don't overwrite it.
+        mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+      }
 
-      index                    = mImpl->mCornerRadiusIndex;
-      mImpl->mNeedCornerRadius = true;
+      index = mImpl->mCornerRadiusIndex;
 
       // Change shader
       UpdateShader();
index b4fde0a..febd285 100644 (file)
@@ -26,6 +26,8 @@
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
 #include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
+#include <dali/integration-api/debug.h>
 
 namespace Dali
 {
@@ -33,11 +35,73 @@ namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+
+/**
+ * @brief Creates the geometry formed from the vertices and indices
+ *
+ * @param[in]  vertices             The vertices to generate the geometry from
+ * @param[in]  indices              The indices to generate the geometry from
+ * @return The geometry formed from the vertices and indices
+ */
+Geometry GenerateGeometry(const Vector<Vector2>& vertices, const Vector<unsigned short>& indices)
+{
+  Property::Map vertexFormat;
+  vertexFormat["aPosition"] = Property::VECTOR2;
+  VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
+  if(vertices.Size() > 0)
+  {
+    vertexBuffer.SetData(&vertices[0], vertices.Size());
+  }
+
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  if(indices.Size() > 0)
+  {
+    geometry.SetIndexBuffer(&indices[0], indices.Size());
+  }
+
+  return geometry;
+}
+
+/**
+ * @brief Adds the indices to form a quad composed off two triangles where the indices are organised in a grid
+ *
+ * @param[out] indices     The indices to add to
+ * @param[in]  rowIdx      The row index to start the quad
+ * @param[in]  nextRowIdx  The index to the next row
+ */
+void AddQuadIndices(Vector<unsigned short>& indices, unsigned int rowIdx, unsigned int nextRowIdx)
+{
+  indices.PushBack(rowIdx);
+  indices.PushBack(nextRowIdx + 1);
+  indices.PushBack(rowIdx + 1);
+
+  indices.PushBack(rowIdx);
+  indices.PushBack(nextRowIdx);
+  indices.PushBack(nextRowIdx + 1);
+}
+
+/**
+ * @brief Adds the vertices to create for npatch
+ * @param[out] vertices The vertices to add to
+ * @param[in]  x        The x value of vector
+ * @param[in]  y        The y value of vector
+ */
+void AddVertex(Vector<Vector2>& vertices, unsigned int x, unsigned int y)
+{
+  vertices.PushBack(Vector2(x, y));
+}
+
+} //unnamed namespace
+
 VisualFactoryCache::VisualFactoryCache(bool preMultiplyOnLoad)
 : mSvgRasterizeThread(NULL),
   mVectorAnimationManager(),
-  mBrokenImageUrl(""),
-  mPreMultiplyOnLoad(preMultiplyOnLoad)
+  mPreMultiplyOnLoad(preMultiplyOnLoad),
+  mBrokenImageInfoContainer()
 {
 }
 
@@ -104,7 +168,10 @@ ImageAtlasManagerPtr VisualFactoryCache::GetAtlasManager()
   if(!mAtlasManager)
   {
     mAtlasManager = new ImageAtlasManager();
-    mAtlasManager->SetBrokenImage(mBrokenImageUrl);
+    if(!mBrokenImageInfoContainer.empty())
+    {
+      mAtlasManager->SetBrokenImage(mBrokenImageInfoContainer[0].url);
+    }
   }
 
   return mAtlasManager;
@@ -207,20 +274,22 @@ Geometry VisualFactoryCache::CreateGridGeometry(Uint16Pair gridSize)
   return geometry;
 }
 
-Texture VisualFactoryCache::GetBrokenVisualImage()
+Texture VisualFactoryCache::GetBrokenVisualImage(uint32_t brokenIndex)
 {
-  if(!mBrokenImageTexture && mBrokenImageUrl.size())
+  if(!(mBrokenImageInfoContainer[brokenIndex].texture))
   {
-    PixelData          data;
-    Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageUrl);
+    PixelData          pixelData;
+    Devel::PixelBuffer pixelBuffer = LoadImageFromFile(mBrokenImageInfoContainer[brokenIndex].url);
     if(pixelBuffer)
     {
-      data                = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
-      mBrokenImageTexture = Texture::New(Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(), data.GetWidth(), data.GetHeight());
-      mBrokenImageTexture.Upload(data);
+      pixelData                = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+      mBrokenImageInfoContainer[brokenIndex].texture  = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+      mBrokenImageInfoContainer[brokenIndex].texture.Upload(pixelData);
+      mBrokenImageInfoContainer[brokenIndex].width = pixelData.GetWidth();
+      mBrokenImageInfoContainer[brokenIndex].height = pixelData.GetHeight();
     }
   }
-  return mBrokenImageTexture;
+  return mBrokenImageInfoContainer[brokenIndex].texture;
 }
 
 void VisualFactoryCache::SetPreMultiplyOnLoad(bool preMultiply)
@@ -233,16 +302,274 @@ bool VisualFactoryCache::GetPreMultiplyOnLoad()
   return mPreMultiplyOnLoad;
 }
 
-void VisualFactoryCache::SetBrokenImageUrl(const std::string& brokenImageUrl)
+void VisualFactoryCache::SetBrokenImageUrl(const std::vector<std::string>& brokenImageUrlList)
 {
-  mBrokenImageUrl = brokenImageUrl;
+  mBrokenImageInfoContainer.clear();
+  mBrokenImageInfoContainer.assign(brokenImageUrlList.size(), BrokenImageInfo());
+  for(unsigned int i = 0; i < brokenImageUrlList.size(); i++)
+  {
+    mBrokenImageInfoContainer[i].url = brokenImageUrlList[i];
+  }
+}
 
-  if(!mAtlasManager)
+VisualUrl::Type VisualFactoryCache::GetBrokenImageVisualType(int index)
+{
+  return mBrokenImageInfoContainer[index].visualType;
+}
+
+Geometry VisualFactoryCache::CreateNPatchGeometry(Uint16Pair gridSize)
+{
+  uint16_t gridWidth  = gridSize.GetWidth();
+  uint16_t gridHeight = gridSize.GetHeight();
+
+  // Create vertices
+  Vector<Vector2> vertices;
+  vertices.Reserve((gridWidth + 1) * (gridHeight + 1));
+
+  for(int y = 0; y < gridHeight + 1; ++y)
   {
-    mAtlasManager = new ImageAtlasManager();
+    for(int x = 0; x < gridWidth + 1; ++x)
+    {
+      AddVertex(vertices, x, y);
+    }
+  }
+
+  // Create indices
+  Vector<unsigned short> indices;
+  indices.Reserve(gridWidth * gridHeight * 6);
+
+  unsigned int rowIdx     = 0;
+  unsigned int nextRowIdx = gridWidth + 1;
+  for(int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx)
+  {
+    for(int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx)
+    {
+      AddQuadIndices(indices, rowIdx, nextRowIdx);
+    }
+  }
+
+  return GenerateGeometry(vertices, indices);
+}
+
+Geometry VisualFactoryCache::GetNPatchGeometry(int index)
+{
+  Geometry          geometry;
+  const NPatchData* data;
+  if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+  {
+    if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
+    {
+      geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
+      if(!geometry)
+      {
+        geometry = CreateNPatchGeometry(Uint16Pair(3,3));
+        SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
+      }
+    }
+    else if(data->GetStretchPixelsX().Size() > 0 || data->GetStretchPixelsY().Size() > 0)
+    {
+      Uint16Pair gridSize(2 * data->GetStretchPixelsX().Size() + 1, 2 * data->GetStretchPixelsY().Size() + 1);
+      geometry = CreateNPatchGeometry(gridSize);
+    }
+  }
+  else
+  {
+    // no N patch data so use default geometry
+    geometry = GetGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY);
+    if(!geometry)
+    {
+      geometry = CreateNPatchGeometry(Uint16Pair(3,3));
+      SaveGeometry(VisualFactoryCache::NINE_PATCH_GEOMETRY, geometry);
+    }
+  }
+  return geometry;
+}
+
+Shader VisualFactoryCache::GetNPatchShader(int index)
+{
+  Shader            shader;
+  const NPatchData* data;
+  // 0 is either no data (load failed?) or no stretch regions on image
+  // for both cases we use the default shader
+  NPatchUtility::StretchRanges::SizeType xStretchCount = 0;
+  NPatchUtility::StretchRanges::SizeType yStretchCount = 0;
+
+  // ask loader for the regions
+  if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data))
+  {
+    xStretchCount = data->GetStretchPixelsX().Count();
+    yStretchCount = data->GetStretchPixelsY().Count();
+  }
+
+  if(DALI_LIKELY((xStretchCount == 0 && yStretchCount == 0)))
+  {
+    shader = GetShader(VisualFactoryCache::NINE_PATCH_SHADER);
+    if(DALI_UNLIKELY(!shader))
+    {
+      shader = Shader::New(SHADER_NPATCH_VISUAL_3X3_SHADER_VERT, SHADER_NPATCH_VISUAL_SHADER_FRAG);
+
+      // Only cache vanilla 9 patch shaders
+      SaveShader(VisualFactoryCache::NINE_PATCH_SHADER, shader);
+    }
+  }
+  else if(xStretchCount > 0 || yStretchCount > 0)
+  {
+    std::stringstream vertexShader;
+    vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
+                 << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
+                 << SHADER_NPATCH_VISUAL_SHADER_VERT;
+    shader = Shader::New(vertexShader.str(), SHADER_NPATCH_VISUAL_SHADER_FRAG);
+  }
+  return shader;
+}
+
+void VisualFactoryCache::RegisterStretchProperties(Renderer& renderer, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent)
+{
+  uint16_t     prevEnd     = 0;
+  uint16_t     prevFix     = 0;
+  uint16_t     prevStretch = 0;
+  unsigned int i           = 1;
+  for(NPatchUtility::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i)
+  {
+    uint16_t start = it->GetX();
+    uint16_t end   = it->GetY();
+
+    uint16_t fix     = prevFix + start - prevEnd;
+    uint16_t stretch = prevStretch + end - start;
+
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    renderer.RegisterProperty(uniform.str(), Vector2(fix, stretch));
+
+    prevEnd     = end;
+    prevFix     = fix;
+    prevStretch = stretch;
+  }
+
+  {
+    prevFix += imageExtent - prevEnd;
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    renderer.RegisterProperty(uniform.str(), Vector2(prevFix, prevStretch));
+  }
+}
+
+void VisualFactoryCache::ApplyTextureAndUniforms(Renderer& renderer, int index)
+{
+  const NPatchData* data;
+  TextureSet        textureSet;
+  if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+  {
+    textureSet = data->GetTextures();
+    mBrokenImageInfoContainer[index].texture = data->GetTextures().GetTexture(0);
+
+    if(data->GetStretchPixelsX().Size() == 1 && data->GetStretchPixelsY().Size() == 1)
+    {
+      //special case for 9 patch
+      Uint16Pair stretchX = data->GetStretchPixelsX()[0];
+      Uint16Pair stretchY = data->GetStretchPixelsY()[0];
+
+      uint16_t stretchWidth  = (stretchX.GetY() >= stretchX.GetX()) ? stretchX.GetY() - stretchX.GetX() : 0;
+      uint16_t stretchHeight = (stretchY.GetY() >= stretchY.GetX()) ? stretchY.GetY() - stretchY.GetX() : 0;
+
+      renderer.RegisterProperty("uFixed[0]", Vector2::ZERO);
+      renderer.RegisterProperty("uFixed[1]", Vector2(stretchX.GetX(), stretchY.GetX()));
+      renderer.RegisterProperty("uFixed[2]", Vector2(data->GetCroppedWidth() - stretchWidth, data->GetCroppedHeight() - stretchHeight));
+      renderer.RegisterProperty("uStretchTotal", Vector2(stretchWidth, stretchHeight));
+    }
+    else
+    {
+      renderer.RegisterProperty("uNinePatchFactorsX[0]", Vector2::ZERO);
+      renderer.RegisterProperty("uNinePatchFactorsY[0]", Vector2::ZERO);
+
+      RegisterStretchProperties(renderer, "uNinePatchFactorsX", data->GetStretchPixelsX(), data->GetCroppedWidth());
+      RegisterStretchProperties(renderer, "uNinePatchFactorsY", data->GetStretchPixelsY(), data->GetCroppedHeight());
+    }
+    renderer.SetTextures(textureSet);
+  }
+}
+
+void VisualFactoryCache::UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size)
+{
+  // Load Information for broken image
+  for(uint32_t index = 0; index < mBrokenImageInfoContainer.size(); index++)
+  {
+    if(mBrokenImageInfoContainer[index].width == 0 && mBrokenImageInfoContainer[index].height == 0)
+    {
+      if(!mBrokenImageInfoContainer[index].url.empty())
+      {
+        VisualUrl visualUrl(mBrokenImageInfoContainer[index].url);
+        mBrokenImageInfoContainer[index].visualType = visualUrl.GetType();
+        if(mBrokenImageInfoContainer[index].visualType == VisualUrl::Type::N_PATCH)
+        {
+          const NPatchData* data;
+          Rect<int> border;
+          mBrokenImageInfoContainer[index].npatchId = mNPatchLoader.Load( mTextureManager, NULL, mBrokenImageInfoContainer[index].url, border, mPreMultiplyOnLoad, true);
+          if(mNPatchLoader.GetNPatchData(mBrokenImageInfoContainer[index].npatchId, data) && data->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
+          {
+            mBrokenImageInfoContainer[index].width = data->GetCroppedWidth();
+            mBrokenImageInfoContainer[index].height = data->GetCroppedHeight();
+          }
+          else
+          {
+            DALI_LOG_ERROR("Can't update renderer for broken image. maybe image loading is failed [path:%s] \n",mBrokenImageInfoContainer[index].url.c_str());
+          }
+        }
+        else
+        {
+          GetBrokenVisualImage(index);
+        }
+      }
+    }
+  }
+
+  // Set Texutre to renderer
+  int brokenIndex = GetProperBrokenImageIndex(size);
+  if(GetBrokenImageVisualType(brokenIndex) == VisualUrl::N_PATCH)
+  {
+    // Set geometry and shader for npatch
+    Geometry geometry = GetNPatchGeometry(brokenIndex);
+    Shader shader = GetNPatchShader(brokenIndex);
+    renderer.SetGeometry(geometry);
+    renderer.SetShader(shader);
+    ApplyTextureAndUniforms(renderer, brokenIndex);
+  }
+  else
+  {
+    Texture brokenImage = GetBrokenVisualImage(brokenIndex);
+    TextureSet textureSet = TextureSet::New();
+    textureSet.SetTexture(0u, brokenImage);
+    renderer.SetTextures(textureSet);
+  }
+}
+
+int32_t VisualFactoryCache::GetProperBrokenImageIndex(const Vector2& size)
+{
+  // Sets the default broken type
+  int32_t returnIndex = 0;
+  if((size.width == 0 || size.height == 0))
+  {
+    // To do : Need to add observer about size
+    return returnIndex;
+  }
+
+  // Find the proper value if we know the size of the image
+  for(int32_t index = static_cast<int32_t>(mBrokenImageInfoContainer.size()) - 1; index >= 0; index--)
+  {
+    // Skip if the value is not set
+    if(mBrokenImageInfoContainer[index].width == 0 || mBrokenImageInfoContainer[index].height == 0)
+    {
+      continue;
+    }
+
+    if(mBrokenImageInfoContainer[index].width < size.width && mBrokenImageInfoContainer[index].height < size.height)
+    {
+      returnIndex = index;
+      break;
+    }
   }
 
-  mAtlasManager->SetBrokenImage(mBrokenImageUrl);
+  return returnIndex;
 }
 
 } // namespace Internal
index 6e8f37d..b23c010 100644 (file)
@@ -28,6 +28,7 @@
 #include <dali-toolkit/internal/visuals/npatch-loader.h>
 #include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
 #include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
 
 namespace Dali
 {
@@ -177,12 +178,6 @@ public:
   static Geometry CreateGridGeometry(Uint16Pair gridSize);
 
   /**
-   * @brief Returns a new Texture to use when a visual has failed to correctly render
-   * @return The broken image texture.
-   */
-  Texture GetBrokenVisualImage();
-
-  /**
    * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
    */
   void SetPreMultiplyOnLoad(bool preMultiply);
@@ -194,9 +189,16 @@ public:
 
   /**
    * @brief Set an image to be used when a visual has failed to correctly render
-   * @param[in] brokenImageUrl The broken image url.
+   * @param[in] brokenImageUrlList The broken image url list
    */
-  void SetBrokenImageUrl(const std::string& brokenImageUrl);
+  void SetBrokenImageUrl(const std::vector<std::string>& brokenImageUrlList);
+
+  /**
+   * @brief Update the broken image Renderer object
+   * @param[in,out] renderer renderer for broken image
+   * @param[in] size the size of actor
+   */
+  void UpdateBrokenImageRenderer(Renderer& renderer, const Vector2& size);
 
 public:
   /**
@@ -241,17 +243,108 @@ protected:
   VisualFactoryCache& operator=(const VisualFactoryCache& rhs);
 
 private:
+  /**
+   * @brief Returns a cached Texture to use when a visual has failed to correctly render
+   * @param[in] brokenIndex The index of broken image
+   *
+   * @return The broken image texture.
+   */
+  Texture GetBrokenVisualImage(uint32_t brokenIndex);
+
+  /**
+   * @brief Gets the Proper broken image index
+   * @param[in] size The size of actor
+   *
+   * @return The index of broken image
+   */
+  int32_t GetProperBrokenImageIndex(const Vector2& size);
+
+  /**
+   * @brief Apply a texture and uniforms
+   *
+   * @param[in,out] renderer The renderer for broken image
+   * @param[in] index The index of broken image
+   */
+  void ApplyTextureAndUniforms(Renderer& renderer, int index);
+
+  /**
+   * @brief Creates a Npatch Geometry object
+   *
+   * @param[in] gridSize The gridSize for creating a geometry
+   * @return The Geometry for NPatch
+   */
+  Geometry CreateNPatchGeometry(Uint16Pair gridSize);
+
+  /**
+   * @brief Gets a geometry for npatch image
+   *
+   * @param[in] index the index of broken image
+   * @return The Geometry for NPatch
+   */
+  Geometry GetNPatchGeometry(int index);
+
+  /**
+   * @brief Gets the Npatch Shader object
+   *
+   * @param[in] index The index of broken image
+   * @return The Shader for NPatch
+   */
+  Shader GetNPatchShader(int index);
+
+  /**
+   * @brief Registers a properties for Stretch Ranges
+   *
+   * @param[in,out] renderer The renderer for broken image
+   * @param[in] uniformName The name of the uniform
+   * @param[in] stretchPixels The stretchable pixels in the cropped image space
+   * @param[in] imageExtent The imageExtent
+   */
+  void RegisterStretchProperties(Renderer& renderer, const char* uniformName, const NPatchUtility::StretchRanges& stretchPixels, uint16_t imageExtent);
+
+  /**
+   * @brief Returns a broken image type
+   * @param[in] index BrokenImage index
+   * @return The broken image type.
+   */
+  VisualUrl::Type GetBrokenImageVisualType(int index);
+
+private:
+  struct BrokenImageInfo
+  {
+    BrokenImageInfo()
+    :visualType(),
+     url(""),
+     npatchId(NPatchData::INVALID_NPATCH_DATA_ID),
+     texture(),
+     width(0),
+     height(0)
+    {
+    }
+
+    ~BrokenImageInfo()
+    {
+    }
+
+    // Data
+    VisualUrl::Type                         visualType;
+    std::string                             url;
+    NPatchData::NPatchDataId                npatchId;
+    Texture                                 texture;
+    uint32_t                                width;
+    uint32_t                                height;
+  };
+
   Geometry mGeometry[GEOMETRY_TYPE_MAX + 1];
   Shader   mShader[SHADER_TYPE_MAX + 1];
 
   ImageAtlasManagerPtr                    mAtlasManager;
   TextureManager                          mTextureManager;
   NPatchLoader                            mNPatchLoader;
-  Texture                                 mBrokenImageTexture;
+
   SvgRasterizeThread*                     mSvgRasterizeThread;
   std::unique_ptr<VectorAnimationManager> mVectorAnimationManager;
-  std::string                             mBrokenImageUrl;
   bool                                    mPreMultiplyOnLoad;
+  std::vector<BrokenImageInfo>            mBrokenImageInfoContainer;
 };
 
 } // namespace Internal
index 8c4b2f8..112fdd3 100644 (file)
@@ -91,19 +91,15 @@ void VisualFactory::OnStyleChangedSignal(Toolkit::StyleManager styleManager, Sty
 {
   if(type == StyleChange::THEME_CHANGE)
   {
-    const std::string imageDirPath   = AssetManager::GetDaliImagePath();
-    std::string       brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
-
-    Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
-    config["brokenImageUrl"].Get(brokenImageUrl);
-
-    if(mFactoryCache)
-    {
-      mFactoryCache->SetBrokenImageUrl(brokenImageUrl);
-    }
+    SetBrokenImageUrl(styleManager);
   }
 }
 
+void VisualFactory::OnBrokenImageChangedSignal(Toolkit::StyleManager styleManager)
+{
+  SetBrokenImageUrl(styleManager);
+}
+
 Toolkit::Visual::Base VisualFactory::CreateVisual(const Property::Map& propertyMap)
 {
   Visual::BasePtr visualPtr;
@@ -154,6 +150,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual(const Property::Map& propertyM
                 visualPtr = NPatchVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap);
                 break;
               }
+              case VisualUrl::TVG:
               case VisualUrl::SVG:
               {
                 visualPtr = SvgVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap);
@@ -318,6 +315,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual(const std::string& url, ImageD
         visualPtr = NPatchVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
         break;
       }
+      case VisualUrl::TVG:
       case VisualUrl::SVG:
       {
         visualPtr = SvgVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
@@ -370,24 +368,43 @@ Internal::TextureManager& VisualFactory::GetTextureManager()
   return GetFactoryCache().GetTextureManager();
 }
 
+void VisualFactory::SetBrokenImageUrl(Toolkit::StyleManager& styleManager)
+{
+  const std::string imageDirPath   = AssetManager::GetDaliImagePath();
+  std::string       brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
+  std::vector<std::string> customBrokenImageUrlList;
+
+  if(styleManager)
+  {
+    customBrokenImageUrlList = Toolkit::DevelStyleManager::GetBrokenImageUrlList(styleManager);
+    if(customBrokenImageUrlList.size() == 0)
+    {
+      Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
+      config["brokenImageUrl"].Get(brokenImageUrl);
+      customBrokenImageUrlList.push_back(brokenImageUrl);
+    }
+    mFactoryCache->SetBrokenImageUrl(customBrokenImageUrlList);
+  }
+  else
+  {
+    // Set default image
+    customBrokenImageUrlList.push_back(brokenImageUrl);
+    mFactoryCache->SetBrokenImageUrl(customBrokenImageUrlList);
+  }
+}
+
 Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
 {
   if(!mFactoryCache)
   {
     mFactoryCache = std::unique_ptr<VisualFactoryCache>(new VisualFactoryCache(mPreMultiplyOnLoad));
-
-    const std::string imageDirPath   = AssetManager::GetDaliImagePath();
-    std::string       brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
-
     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
     if(styleManager)
     {
-      Property::Map config = Toolkit::DevelStyleManager::GetConfigurations(styleManager);
-      config["brokenImageUrl"].Get(brokenImageUrl);
       styleManager.StyleChangedSignal().Connect(mSlotDelegate, &VisualFactory::OnStyleChangedSignal);
+      Toolkit::DevelStyleManager::BrokenImageChangedSignal(styleManager).Connect(mSlotDelegate, &VisualFactory::OnBrokenImageChangedSignal);
     }
-
-    mFactoryCache->SetBrokenImageUrl(brokenImageUrl);
+    SetBrokenImageUrl(styleManager);
   }
   return *mFactoryCache;
 }
index f038301..a5ecda8 100644 (file)
@@ -58,6 +58,13 @@ public:
   void OnStyleChangedSignal(Toolkit::StyleManager styleManager, StyleChange::Type type);
 
   /**
+   * @brief BrokenImageChanged callback
+   *
+   * @param[in] styleManager Handle for style manager.
+   */
+  void OnBrokenImageChangedSignal(Toolkit::StyleManager styleManager);
+
+  /**
    * @copydoc Toolkit::VisualFactory::CreateVisual( const Property::Map& )
    */
   Toolkit::Visual::Base CreateVisual(const Property::Map& propertyMap);
@@ -90,6 +97,12 @@ protected:
 
 private:
   /**
+   * @brief Set the Broken Image url
+   * @param[in] styleManager The instance of StyleManager
+   */
+  void SetBrokenImageUrl(Toolkit::StyleManager& styleManager);
+
+  /**
    * Get the factory cache, creating it if necessary.
    */
   Internal::VisualFactoryCache& GetFactoryCache();
index 30d9c02..0ad5778 100644 (file)
@@ -118,7 +118,9 @@ VisualUrl::Type ResolveType(const std::string& url)
     char         GIF[4]    = {'f', 'i', 'g', '.'};
     char         WEBP[5]   = {'p', 'b', 'e', 'w', '.'};
     char         JSON[5]   = {'n', 'o', 's', 'j', '.'};
+    char         TVG[4]    = {'g', 'v', 't', '.'};
     unsigned int svgScore  = 0;
+    unsigned int tvgScore  = 0;
     unsigned int gifScore  = 0;
     unsigned int webpScore = 0;
     unsigned int jsonScore = 0;
@@ -135,6 +137,14 @@ VisualUrl::Type ResolveType(const std::string& url)
           return VisualUrl::SVG;
         }
       }
+      if((offsetFromEnd < sizeof(TVG)) && (currentChar == TVG[offsetFromEnd]))
+      {
+        // early out if TVG as can't be used in N patch for now
+        if(++tvgScore == sizeof(TVG))
+        {
+          return VisualUrl::TVG;
+        }
+      }
       if((offsetFromEnd < sizeof(GIF)) && (currentChar == GIF[offsetFromEnd]))
       {
         // early out if GIF as can't be used in N patch for now
index 555e383..08a276a 100644 (file)
@@ -38,7 +38,8 @@ public:
     SVG,
     GIF,
     WEBP,
-    JSON
+    JSON,
+    TVG
   };
 
   enum ProtocolType
diff --git a/dali-toolkit/public-api/controls/gl-view/gl-view.cpp b/dali-toolkit/public-api/controls/gl-view/gl-view.cpp
new file mode 100644 (file)
index 0000000..b5f6a8c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/controls/gl-view/gl-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/gl-view/gl-view-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+GlView::GlView()
+{
+}
+
+GlView::GlView(const GlView& GlView) = default;
+
+GlView::GlView(GlView&& rhs) = default;
+
+GlView& GlView::operator=(const GlView& GlView) = default;
+
+GlView& GlView::operator=(GlView&& rhs) = default;
+
+GlView::~GlView()
+{
+}
+
+GlView GlView::New(ColorFormat colorFormat)
+{
+  return Internal::GlView::New(colorFormat);
+}
+
+GlView GlView::DownCast(BaseHandle handle)
+{
+  return Control::DownCast<GlView, Internal::GlView>(handle);
+}
+
+void GlView::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
+{
+  Dali::Toolkit::GetImpl(*this).RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback);
+}
+
+void GlView::SetResizeCallback(CallbackBase* resizeCallback)
+{
+  Dali::Toolkit::GetImpl(*this).SetResizeCallback(resizeCallback);
+}
+
+bool GlView::SetGraphicsConfig(bool depth, bool stencil, int msaa, GraphicsApiVersion version)
+{
+  return Dali::Toolkit::GetImpl(*this).SetGraphicsConfig(depth, stencil, msaa, version);
+}
+
+void GlView::SetRenderingMode(RenderingMode mode)
+{
+  Dali::Toolkit::GetImpl(*this).SetRenderingMode(mode);
+}
+
+Dali::Toolkit::GlView::RenderingMode GlView::GetRenderingMode() const
+{
+  return Dali::Toolkit::GetImpl(*this).GetRenderingMode();
+}
+
+void GlView::RenderOnce()
+{
+  Dali::Toolkit::GetImpl(*this).RenderOnce();
+}
+
+GlView::GlView(Internal::GlView& implementation)
+: Control(implementation)
+{
+}
+
+GlView::GlView(Dali::Internal::CustomActor* internal)
+: Control(internal)
+{
+  VerifyCustomActorPointer<Internal::GlView>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/gl-view/gl-view.h b/dali-toolkit/public-api/controls/gl-view/gl-view.h
new file mode 100644 (file)
index 0000000..be13db9
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef DALI_TOOLKIT_GL_VIEW_H
+#define DALI_TOOLKIT_GL_VIEW_H
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal DALI_INTERNAL
+{
+class GlView;
+}
+
+/**
+ * @brief GlView is a class for rendering with GL
+ *
+ * GlView allows drawing with OpenGL.
+ * GlView creates a GL context, a GL surface and a render thread.
+ * The render thread invokes user's callbacks.
+ *
+ */
+class DALI_TOOLKIT_API GlView : public Dali::Toolkit::Control
+{
+public:
+  /**
+   * @brief Enumeration for rendering mode
+   *
+   * This Enumeration is used to choose the rendering mode.
+   * It has two options.
+   * One of them is continuous mode. It is rendered continuously.
+   * The other is on demand mode. It is rendered by application.
+   */
+  enum class RenderingMode
+  {
+    CONTINUOUS, ///< continuous mode
+    ON_DEMAND   ///< on demand by application
+  };
+
+  /**
+   * @brief Enumeration for Graphics API version
+   *
+   * This Enumeration is used to set a GLES version for EGL configuration.
+   */
+  enum class GraphicsApiVersion
+  {
+    GLES_VERSION_2_0 = 0, ///< GLES version 2.0
+    GLES_VERSION_3_0,     ///< GLES version 3.0
+  };
+
+  /**
+   * @brief Enumeration for color buffer format
+   *
+   * This Enumeration is used to set a color buffer format of GlView
+   */
+  enum class ColorFormat
+  {
+    RGB888,  ///< 8 red bits, 8 green bits, 8 blue bits
+    RGBA8888 ///< 8 red bits, 8 green bits, 8 blue bits, alpha 8 bits
+  };
+
+  /**
+   * @brief Creates a GlView control.
+   * @param[in] colorFormat the format of the color buffer.
+   * @return A handle to a GlView control
+   */
+  static GlView New(ColorFormat colorFormat);
+
+  /**
+   * @brief Creates an uninitialized GlView.
+   */
+  GlView();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~GlView();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] GlView GlView to copy. The copied GlView will point at the same implementation
+   */
+  GlView(const GlView& GlView);
+
+  /**
+   * @brief Move constructor
+   *
+   * @param[in] rhs A reference to the moved handle
+   */
+  GlView(GlView&& rhs);
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] GlView The GlView to assign from
+   * @return A reference to this
+   */
+  GlView& operator=(const GlView& GlView);
+
+  /**
+   * @brief Move assignment
+   *
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  GlView& operator=(GlView&& rhs);
+
+  /**
+   * @brief Downcasts a handle to GlView handle.
+   *
+   * If handle points to a GlView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to a GlView or an uninitialized handle
+   */
+  static GlView DownCast(BaseHandle handle);
+
+  /**
+   * @brief Registers GL callback functions for GlView.
+   *
+   * @param[in] initCallback  the callback function to create GL resources.
+   * @param[in] renderFrameCallback the callback function to render for the frame.
+   * @param[in] terminateCallback the callback function to clean-up GL resources.
+   *
+   * A initCallback of the following type have to be used:
+   * @code
+   *   void intializeGL();
+   * @endcode
+   * This callback will be called before renderFrame callback is called once.
+   *
+   * A renderFrameCallback of the following type have to be used:
+   * @code
+   *   int renderFrameGL();
+   * @endcode
+   * If the return value of this callback is not 0, the eglSwapBuffers() will be called.
+   *
+   * A terminateCallback of the following type have to be used:
+   * @code
+   *   void terminateGL();
+   * @endcode
+   * This callback is called when GlView is deleted.
+   *
+   * @note Ownership of the callbacks is passed onto this class.
+   * <b>You can't call Dali APIs in your callbacks because it is invoked in GlView's own render thread.</b>
+   * And this must be called before adding GlView to the scene.
+   */
+  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+
+  /**
+   * @brief Sets the ResizeCallback of the GlView.
+   * When GlView is resized, ResizeCallback would be invoked.
+   * You can get the resized width and height of the GlView.
+   *
+   * @param[in] resizeCallback The ResizeCallback function
+   *
+   * A resizeCallback of the following type have to be used:
+   * @code
+   *   void resizeCallback(int width, int height);
+   * @endcode
+   *
+   * @note Ownership of the callback is passed onto this class.
+   * <b>You can't call Dali APIs in your callback because it is invoked in GlView's own render thread.</b>
+   * And this must be called before adding GlView to the scene.
+   */
+  void SetResizeCallback(CallbackBase* resizeCallback);
+
+  /**
+   * @brief Sets the rendering mode.
+   *
+   * @param[in] mode the rendering mode for GlView
+   *
+   * @note The default Rendering mode is CONTINUOUS.
+   * If ON_DEMAND mode is set, it is rendered by RenderOnce()
+   */
+  void SetRenderingMode(RenderingMode mode);
+
+  /**
+   * @brief Gets the rendering mode.
+   */
+  RenderingMode GetRenderingMode() const;
+
+  /**
+   * @brief Sets egl configuration for GlView
+   *
+   * @param[in] depth the flag of depth buffer. If the value is true, 24bit depth buffer is enabled.
+   * @param[in] stencil the flag of stencil. If the value is true, 8bit stencil buffer is enabled.
+   * @param[in] msaa the expected sampling number per pixel.
+   * @param[in] version the graphics API version
+   * @return True if the config exists, false otherwise.
+   */
+  bool SetGraphicsConfig(bool depth, bool stencil, int msaa, GraphicsApiVersion version);
+
+  /**
+   * @brief Renders once more even if GL render functions are not added to idler.
+   * @note Will not work if the window is hidden or GL render functions are added to idler
+   */
+  void RenderOnce();
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @param[in] implementation The GlView implementation
+   */
+  DALI_INTERNAL GlView(Internal::GlView& implementation);
+
+  /**
+   * @brief Allows the creation of this GlView from an Internal::CustomActor pointer.
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL GlView(Dali::Internal::CustomActor* internal);
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_GL_VIEW_H
index 805e7c6..9935284 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 44;
+const unsigned int TOOLKIT_MICRO_VERSION = 48;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 7b72745..ffd306b 100644 (file)
@@ -27,6 +27,7 @@ SET( public_api_src_files
   ${public_api_src_dir}/controls/text-controls/text-field.cpp
   ${public_api_src_dir}/controls/video-view/video-view.cpp
   ${public_api_src_dir}/controls/camera-view/camera-view.cpp
+  ${public_api_src_dir}/controls/gl-view/gl-view.cpp
   ${public_api_src_dir}/image-loader/image.cpp
   ${public_api_src_dir}/image-loader/image-url.cpp
   ${public_api_src_dir}/image-loader/async-image-loader.cpp
@@ -141,6 +142,10 @@ SET( public_api_camera_view_header_files
   ${public_api_src_dir}/controls/camera-view/camera-view.h
 )
 
+SET( public_api_gl_view_header_files
+  ${public_api_src_dir}/controls/gl-view/gl-view.h
+)
+
 SET( public_api_visuals_header_files
   ${public_api_src_dir}/visuals/border-visual-properties.h
   ${public_api_src_dir}/visuals/color-visual-properties.h
@@ -186,4 +191,5 @@ SET( PUBLIC_API_HEADERS ${PUBLIC_API_HEADERS}
   ${public_api_video_view_header_files}
   ${public_api_visuals_header_files}
   ${public_api_camera_view_header_files}
+  ${public_api_gl_view_header_files}
 )
index 0c218ca..1cf7e71 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.0.44
+Version:    2.0.48
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT