Merge "Fixed an error adding duplicate primary position.y" into devel/master
authorJinho, Lee <jeano.lee@samsung.com>
Wed, 21 Jun 2017 01:30:00 +0000 (01:30 +0000)
committerGerrit Code Review <gerrit@review.ap-northeast-2.compute.internal>
Wed, 21 Jun 2017 01:30:00 +0000 (01:30 +0000)
22 files changed:
automated-tests/resources/mask.png [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h
automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
dali-toolkit/devel-api/controls/control-wrapper-impl.cpp
dali-toolkit/devel-api/controls/control-wrapper-impl.h
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/popup/popup-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/text/multi-language-support-impl.cpp
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/texture-manager.cpp
dali-toolkit/internal/visuals/texture-manager.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

diff --git a/automated-tests/resources/mask.png b/automated-tests/resources/mask.png
new file mode 100644 (file)
index 0000000..0032f29
Binary files /dev/null and b/automated-tests/resources/mask.png differ
index 248276e..dd6ba24 100644 (file)
@@ -173,9 +173,16 @@ inline bool CompareType<Property::Value>(Property::Value q1, Property::Value q2,
       result = CompareType<Quaternion>(a, b, epsilon);
       break;
     }
+    case Property::STRING:
+    {
+      std::string a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = (a.compare(b) == 0);
+      break;
+    }
     case Property::MATRIX:
     case Property::MATRIX3:
-    case Property::STRING:
     case Property::ARRAY:
     case Property::MAP:
     {
index 3ea0786..c62e11c 100644 (file)
 
 #include <dali.h>
 #include <dali/public-api/dali-core.h>
+#include <dali/devel-api/actors/custom-actor-devel.h>
+#include <dali/devel-api/object/csharp-type-registry.h>
 #include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/controls/control-wrapper.h>
 #include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
@@ -52,13 +55,14 @@ bool gOnRelayout = false;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+
 namespace Impl
 {
 struct TestCustomControl : public Toolkit::Internal::ControlWrapper
 {
   /**
-  * Constructor
-  */
+   * Constructor
+   */
   TestCustomControl()  : Toolkit::Internal::ControlWrapper( CustomControlBehaviour( Toolkit::Internal::ControlWrapper::DISABLE_STYLE_CHANGE_SIGNALS |
           Toolkit::Internal::ControlWrapper::REQUIRES_KEYBOARD_NAVIGATION_SUPPORT )) ,
           mDaliProperty( Property::INVALID_INDEX ),
@@ -97,26 +101,33 @@ struct TestCustomControl : public Toolkit::Internal::ControlWrapper
   virtual void OnStageConnection( int depth )
   {
     mDepth = depth;
+    Control::OnStageConnection(depth);
   }
   virtual void OnStageDisconnection()
   {
+    Control::OnStageDisconnection();
   }
   virtual void OnChildAdd( Actor& child )
   {
+    Control::OnChildAdd(child);
   }
   virtual void OnChildRemove( Actor& child )
   {
+    Control::OnChildRemove(child);
   }
   virtual void OnPropertySet( Property::Index index, Property::Value propertyValue )
   {
+    Control::OnPropertySet(index, propertyValue);
   }
   virtual void OnSizeSet( const Vector3& targetSize )
   {
     mSizeSet = targetSize;
+    Control::OnSizeSet( targetSize );
   }
   virtual void OnSizeAnimation( Animation& animation, const Vector3& targetSize )
   {
     mTargetSize = targetSize;
+    Control::OnSizeAnimation( animation, targetSize );
   }
   virtual bool OnTouchEvent( const TouchEvent& event )
   {
@@ -155,9 +166,27 @@ struct TestCustomControl : public Toolkit::Internal::ControlWrapper
     return 0.0f;
   }
 
+  void TestRegisterVisual( Property::Index index, Toolkit::Visual::Base visual )
+  {
+    ControlWrapper::RegisterVisual( index, visual );
+
+    VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
+    if( iter == mRegisteredVisualIndices.end() )
+    {
+      mRegisteredVisualIndices.push_back(index);
+    }
+  }
+
   virtual void OnRelayout( const Vector2& size, RelayoutContainer& container )
   {
     gOnRelayout = true;
+
+    for( VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end() ; ++iter )
+    {
+      Visual::Base visual = GetVisual(*iter);
+      Property::Map map; // empty map enforces defaults
+      visual.SetTransformAndSize( map, size );
+    }
   }
 
   virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
@@ -216,13 +245,19 @@ struct TestCustomControl : public Toolkit::Internal::ControlWrapper
   Vector3 mTargetSize;
   bool mNego;
   unsigned int mDepth;
+
+  typedef std::vector<Property::Index> VisualIndices;
+  VisualIndices mRegisteredVisualIndices;
 };
 
+
+
 }
 
-static std::string customControlTypeName = "TestCustomControl";
+static std::string customControlTypeName = "MyTestCustomControl";
 static TypeRegistration customControl( customControlTypeName, typeid(Dali::Toolkit::Control), NULL );
 
+
 int UtcDaliControlWrapperConstructor(void)
 {
   ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
@@ -236,6 +271,11 @@ int UtcDaliControlWrapperConstructor(void)
 
   DALI_TEST_CHECK( ControlWrapper::DownCast( controlWrapper ) );
 
+  Dali::TypeInfo typeInfo = DevelCustomActor::GetTypeInfo( controlWrapper );
+
+  DALI_TEST_EQUALS( typeInfo.GetName(), customControlTypeName, TEST_LOCATION);
+
+
   END_TEST;
 }
 
@@ -683,3 +723,87 @@ int UtcDaliControlWrapperTypeRegistryCreation(void)
 
   END_TEST;
 }
+
+void SetProperty(BaseObject* object, const char* const name, Property::Value* value)
+{
+}
+Property::Value* GetProperty(BaseObject* object, const char* const name )
+{
+  return NULL;
+}
+
+int UtcDaliControlWrapperAnimateVisual(void)
+{
+  tet_infoline("Test that the control wrapper's visuals can be animated by name when registered");
+
+  ToolkitTestApplication application;
+  Test::ObjectDestructionTracker objectDestructionTracker;
+
+  {
+    Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+    ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+    Property::Index index = Control::CONTROL_PROPERTY_END_INDEX+1;
+    std::string visualName("colorVisual");
+    CSharpTypeRegistry::RegisterProperty( customControlTypeName, visualName, index, Property::VECTOR4, SetProperty, GetProperty );
+
+    objectDestructionTracker.Start( controlWrapper );
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+    Toolkit::Visual::Base visual;
+
+    Property::Map map;
+    map[Visual::Property::TYPE] = Visual::COLOR;
+    map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+    visual = visualFactory.CreateVisual( map );
+    DALI_TEST_CHECK( visual );
+
+    // Register to self
+    controlWrapperImpl->TestRegisterVisual( index, visual );
+
+    Stage::GetCurrent().Add( controlWrapper );
+    controlWrapper.SetSize( 100, 100 );
+    application.SendNotification();
+    application.Render(0); // Trigger animation start
+
+    Property::Map transition;
+    transition["target"] = visualName;
+    transition["property"] = "mixColor";
+    transition["targetValue"] = Color::GREEN;
+    Property::Map animator;
+    animator["alphaFunction"] = "LINEAR";
+    animator["duration"] = 1.0f;
+    animator["delay"] = 0.0f;
+    transition["animator"] = animator;
+
+    TransitionData transitionData = TransitionData::New(transition);
+    Animation anim = DevelControl::CreateTransition( *controlWrapperImpl, transitionData );
+    anim.Play();
+
+    application.SendNotification();
+    application.Render(0); // Trigger animation start
+
+    application.Render(1000); // animation end
+    application.Render(  10);
+
+    Property::Map visualMap;
+    visual.CreatePropertyMap( visualMap );
+    Property::Value* value = visualMap.Find(ColorVisual::Property::MIX_COLOR, "mixColor");
+    DALI_TEST_CHECK( value != NULL );
+    if( value )
+    {
+      Vector4 testColor = value->Get<Vector4>();
+      DALI_TEST_EQUALS( testColor, Color::GREEN, 0.001f, TEST_LOCATION );
+    }
+
+    DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), false, TEST_LOCATION ); // Control not destroyed yet
+    DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( index ), visual, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove( controlWrapper );
+  }
+
+  DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), true, TEST_LOCATION ); // Should be destroyed
+
+  END_TEST;
+}
index a56df48..f6d34b9 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visual-factory/transition-data.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include "dummy-control.h"
 
@@ -48,12 +49,13 @@ void dali_image_visual_cleanup(void)
 
 namespace
 {
-const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/gallery_small-1.jpg";
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/gallery-small-1.jpg";
 const char* TEST_LARGE_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/tbcol.png";
 const char* TEST_SMALL_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/icon-edit.png";
 const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/themes/tizen_theme/logo.png";
 const char* TEST_INVALID_FILE_NAME =  TEST_RESOURCE_DIR  "/invalid.jpg";
 const char* TEST_REMOTE_INVALID_FILE_NAME = "https://www.tizen.org/invalid.png";
+const char* TEST_MASK_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/mask.png";
 }
 
 
@@ -343,7 +345,12 @@ int UtcDaliImageVisualTextureReuse2(void)
 
   DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
   DALI_TEST_EQUALS( drawTrace.CountMethod("DrawArrays"), 2, TEST_LOCATION );
-  DALI_TEST_EQUALS( textureTrace.CountMethod("BindTexture"), 2, TEST_LOCATION );
+  TraceCallStack::NamedParams tex1;
+  tex1["texture"] = "1";
+  TraceCallStack::NamedParams tex2;
+  tex1["texture"] = "2";
+  DALI_TEST_EQUALS( textureTrace.FindMethodAndParams("BindTexture", tex1), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethodAndParams("BindTexture", tex2), true, TEST_LOCATION );
 
   tet_infoline("Test that removing 1 actor deletes it's texture\n");
 
@@ -973,3 +980,107 @@ int UtcDaliImageVisualSetInvalidRemoteImage(void)
 
   END_TEST;
 }
+
+int UtcDaliImageVisualAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( DevelImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(DevelImageVisual::Property::ALPHA_MASK_URL),Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualRemoteAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  const std::string MASK_IMAGE = TEST_REMOTE_IMAGE_FILE_NAME;
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( "alphaMaskUrl", MASK_IMAGE );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(DevelImageVisual::Property::ALPHA_MASK_URL),Property::Value(MASK_IMAGE), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), false, TEST_LOCATION );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsResourceReady( actor ), true, TEST_LOCATION );
+
+  END_TEST;
+}
index 053c79c..bb9ae72 100644 (file)
@@ -1595,17 +1595,18 @@ int utcDaliTextEditorEvent03(void)
   // The stencil actor should have two actors: the renderer and the highlight actor.
   Actor stencil = editor.GetChildAt( 0u );
 
+  // Highlight needs to be drawn before text, so should come first in child order
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
   // The stencil actor has a container with all the actors which contain the text renderers.
-  Actor container = stencil.GetChildAt( 0u );
+  Actor container = stencil.GetChildAt( 1u );
   for( unsigned int index = 0; index < container.GetChildCount(); ++index )
   {
     Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
     DALI_TEST_CHECK( renderer );
   }
 
-  Renderer highlight = stencil.GetChildAt( 1u ).GetRendererAt( 0u );
-  DALI_TEST_CHECK( highlight );
-
   // Double tap out of bounds
   application.ProcessEvent( GenerateTap( Gesture::Possible, 2u, 1u, Vector2( 29.f, 25.0f ) ) );
   application.ProcessEvent( GenerateTap( Gesture::Started, 2u, 1u, Vector2( 29.f, 25.0f ) ) );
index b05305b..2c1aa44 100644 (file)
@@ -1702,17 +1702,18 @@ int utcDaliTextFieldEvent03(void)
   // The offscreen root actor should have two actors: the renderer and the highlight actor.
   Actor stencil = field.GetChildAt( 0u );
 
+  // The highlight actor is drawn first, so is the first actor in the list
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
   // The offscreen root actor has a container with all the actors which contain the text renderers.
-  Actor container = stencil.GetChildAt( 0u );
+  Actor container = stencil.GetChildAt( 1u );
   for( unsigned int index = 0; index < container.GetChildCount(); ++index )
   {
     Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
     DALI_TEST_CHECK( renderer );
   }
 
-  Renderer highlight = stencil.GetChildAt( 1u ).GetRendererAt( 0u );
-  DALI_TEST_CHECK( highlight );
-
   END_TEST;
 }
 
index b8e40b8..2e7e268 100644 (file)
@@ -207,7 +207,7 @@ void TestVisualRender( ToolkitTestApplication& application,
                        Integration::ResourcePointer resourcePtr = Integration::ResourcePointer())
 {
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
 
   if( resourcePtr )
   {
@@ -317,7 +317,7 @@ int UtcDaliVisualFactoryGetColorVisual1(void)
   Visual::Base visual = factory.CreateVisual(propertyMap);
   DALI_TEST_CHECK( visual );
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual );
 
   Vector3 actualValue(Vector4::ZERO);
@@ -346,7 +346,7 @@ int UtcDaliVisualFactoryGetColorVisual2(void)
   Visual::Base visual = factory.CreateVisual( map );
   DALI_TEST_CHECK( visual );
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual );
 
   Vector3 actualValue;
@@ -381,9 +381,9 @@ int UtcDaliVisualFactoryGetBorderVisual1(void)
   Visual::Base visual = factory.CreateVisual(propertyMap);
   DALI_TEST_CHECK( visual );
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   actor.SetSize(200.f, 200.f);
   Stage::GetCurrent().Add( actor );
   visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f));
@@ -429,9 +429,9 @@ int UtcDaliVisualFactoryGetBorderVisual2(void)
   Visual::Base visual = factory.CreateVisual( propertyMap );
   DALI_TEST_CHECK( visual );
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   actor.SetSize(200.f, 200.f);
   Stage::GetCurrent().Add( actor );
   visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f));
@@ -504,7 +504,7 @@ int UtcDaliVisualFactoryGetLinearGradientVisual(void)
   DALI_TEST_CHECK( visual );
 
   // A lookup texture is generated and pass to shader as sampler
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u);
 
   END_TEST;
@@ -541,7 +541,7 @@ int UtcDaliVisualFactoryGetRadialGradientVisual(void)
   DALI_TEST_CHECK( visual );
 
   // A lookup texture is generated and pass to shader as sampler
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u );
 
   Matrix3 alignMatrix( radius, 0.f, 0.f, 0.f, radius, 0.f, center.x, center.y, 1.f );
@@ -581,7 +581,7 @@ int UtcDaliVisualFactoryDefaultOffsetsGradientVisual(void)
   DALI_TEST_CHECK( visual );
 
   // A lookup texture is generated and pass to shader as sampler
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u );
 
   Stage::GetCurrent().Remove( actor );
@@ -623,7 +623,7 @@ int UtcDaliVisualFactoryGetNPatchVisual1(void)
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
 
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u,
                       ImageDimensions(ninePatchImageWidth, ninePatchImageHeight),
                       ninePatchResource );
@@ -641,7 +641,7 @@ int UtcDaliVisualFactoryGetNPatchVisual1(void)
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
 
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u,
                       ImageDimensions(ninePatchImageWidth, ninePatchImageHeight),
                       ninePatchResource );
@@ -673,7 +673,7 @@ int UtcDaliVisualFactoryGetNPatchVisual2(void)
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
 
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u );
 
     DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
@@ -689,7 +689,7 @@ int UtcDaliVisualFactoryGetNPatchVisual2(void)
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
 
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u );
 
     DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
@@ -708,7 +708,7 @@ int UtcDaliVisualFactoryGetNPatchVisual2(void)
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
 
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u );
 
     DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
@@ -749,7 +749,7 @@ int UtcDaliVisualFactoryGetNPatchVisual3(void)
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
 
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u,
                       ImageDimensions(ninePatchImageWidth, ninePatchImageHeight),
                       ninePatchResource );
@@ -769,7 +769,7 @@ int UtcDaliVisualFactoryGetNPatchVisual3(void)
     TestGlAbstraction& gl = application.GetGlAbstraction();
     TraceCallStack& textureTrace = gl.GetTextureTrace();
     textureTrace.Enable(true);
-    DummyControl actor = DummyControl::New();
+    DummyControl actor = DummyControl::New(true);
     TestVisualRender( application, actor, visual, 1u,
                       ImageDimensions(ninePatchImageWidth, ninePatchImageHeight),
                       ninePatchResource );
@@ -807,7 +807,7 @@ int UtcDaliVisualFactoryGetNPatchVisual4(void)
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u,
                     ImageDimensions(ninePatchImageWidth, ninePatchImageHeight),
                     ninePatchResource );
@@ -853,7 +853,7 @@ int UtcDaliVisualFactoryGetNPatchVisual5(void)
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u,
                     ImageDimensions(ninePatchImageWidth, ninePatchImageHeight),
                     ninePatchResource );
@@ -884,7 +884,7 @@ int UtcDaliVisualFactoryGetNPatchVisualN1(void)
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u,
                     ImageDimensions(),
                     Integration::ResourcePointer(bitmap) );
@@ -921,7 +921,7 @@ int UtcDaliVisualFactoryGetNPatchVisualN2(void)
   TraceCallStack& drawTrace = gl.GetDrawTrace();
   drawTrace.Enable(true);
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   TestVisualRender( application, actor, visual, 1u,
                     ImageDimensions(),
                     Integration::ResourcePointer(bitmap) );
@@ -964,9 +964,9 @@ int UtcDaliVisualFactoryGetSvgVisual(void)
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   actor.SetSize( 200.f, 200.f );
   Stage::GetCurrent().Add( actor );
   visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f) );
@@ -1007,7 +1007,7 @@ int UtcDaliVisualFactoryGetSvgVisualLarge(void)
   DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
   actor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); // Only rasterizes when it knows control size.
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   Stage::GetCurrent().Add( actor );
 
   application.SendNotification();
@@ -1042,9 +1042,9 @@ void MeshVisualLoadsCorrectlyTest( Property::Map& propertyMap, ToolkitTestApplic
   DALI_TEST_CHECK( visual );
 
   //Create an actor on stage to house the visual.
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   actor.SetSize( 200.f, 200.f );
   Stage::GetCurrent().Add( actor );
   visual.SetTransformAndSize(DefaultTransform(), Vector2( 200.f, 200.f ) );
@@ -1085,9 +1085,9 @@ void MeshVisualDoesNotLoadCorrectlyTest( Property::Map& propertyMap, ToolkitTest
   DALI_TEST_CHECK( visual );
 
   //Create an actor on stage to house the visual.
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   actor.SetSize( 200.f, 200.f );
   Stage::GetCurrent().Add( actor );
   visual.SetTransformAndSize(DefaultTransform(),  Vector2( 200.f, 200.f ) );
@@ -1391,9 +1391,9 @@ void TestPrimitiveVisualWithProperties( Property::Map& propertyMap, ToolkitTestA
   DALI_TEST_CHECK( visual );
 
   //Create an actor on stage to house the visual.
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
 
   actor.SetSize( 200.f, 200.f );
   Stage::GetCurrent().Add( actor );
@@ -1809,9 +1809,9 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
-  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
   actor.SetSize( 200.0f, 200.0f );
   Stage::GetCurrent().Add( actor );
 
@@ -1898,7 +1898,7 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual2(void)
   TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
   texParameterTrace.Enable( true );
 
-  DummyControl actor = DummyControl::New();
+  DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
   dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
   actor.SetSize( 200.0f, 200.0f );
index 8028707..37def2b 100755 (executable)
@@ -23,6 +23,7 @@
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/actors/custom-actor-devel.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
@@ -179,6 +180,11 @@ void ControlWrapper::ApplyThemeStyle()
   }
 }
 
+Dali::TypeInfo ControlWrapper::GetTypeInfo()
+{
+  return DevelCustomActor::GetTypeInfo(Self());
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 899a575..e5c371d 100755 (executable)
@@ -168,6 +168,13 @@ public: // From Control
    */
   void ApplyThemeStyle();
 
+public:
+  /**
+   * Enable access to non-native type info from native side
+   * @return The type info that was registered on this type
+   */
+  Dali::TypeInfo GetTypeInfo();
+
 protected:
 
   /**
index d2622da..0471ae2 100644 (file)
@@ -64,6 +64,18 @@ enum Type
    */
 
   ATLASING = WRAP_MODE_V + 2,
+
+  /**
+   * @brief URL of a masking image
+   * @details Name "alphaMaskUrl", type Property::STRING, URL of image to apply as
+   * a mask after image loading. If set after the main URL has finished loading, this
+   * may necessitate a re-load of the main image. The alpha mask image will be scaled
+   * on load to match the size of the main image, then applied to the pixel data
+   * before uploading to GL.
+   * @note Optional.
+   */
+
+  ALPHA_MASK_URL = WRAP_MODE_V + 3,
 };
 
 } //namespace Property
index 304ba78..81fa035 100644 (file)
@@ -37,6 +37,7 @@
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
 
 namespace Dali
 {
@@ -439,21 +440,20 @@ void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base
   // ( If the control has been type registered )
   if( visual.GetName().empty() )
   {
-    // Check if the control has been type registered:
-    TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( typeid( mControlImpl ) );
-    if( typeInfo )
+    try
     {
-      // Check if the property index has been registered:
-      Property::IndexContainer indices;
-      typeInfo.GetPropertyIndices( indices );
-      Property::IndexContainer::Iterator iter = std::find( indices.Begin(), indices.End(), index );
-      if( iter != indices.End() )
+      std::string visualName = self.GetPropertyName( index );
+      if( !visualName.empty() )
       {
-        // If it has, then get it's name and use that for the visual
-        std::string visualName = typeInfo.GetPropertyName( index );
+        DALI_LOG_INFO( gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n",
+                       index, visualName.c_str() );
         visual.SetName( visualName );
       }
     }
+    catch( Dali::DaliException e )
+    {
+      DALI_LOG_WARNING( "Attempting to register visual without a registered property, index: %d\n", index );
+    }
   }
 
   if( !visualReplaced ) // New registration entry
@@ -603,11 +603,23 @@ Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData&
 
       if( visual )
       {
+#if defined(DEBUG_ENABLED)
+        Dali::TypeInfo typeInfo;
+        ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
+        if( controlWrapperImpl )
+        {
+          typeInfo = controlWrapperImpl->GetTypeInfo();
+        }
+
+        DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n",
+                       visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" );
+#endif
         Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
         visualImpl.AnimateProperty( transition, *animator );
       }
       else
       {
+        DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
         // Otherwise, try any actor children of control (Including the control)
         Actor child = mControlImpl.Self().FindChildByName( animator->objectName );
         if( child )
index 9794921..7374138 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali/public-api/events/touch-data.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/devel-api/scripting/scripting.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/public-api/size-negotiation/relayout-container.h>
 
 // INTERNAL INCLUDES
@@ -592,6 +593,7 @@ void Popup::SetPopupBackgroundImage( Actor image )
   const bool prevAlter = mAlterAddedChild;
   mAlterAddedChild = false;
   mPopupContainer.Add( mPopupBackgroundImage );
+  DevelActor::LowerToBottom(mPopupBackgroundImage);
   mAlterAddedChild = prevAlter;
 
   if( mTailImage )
index 1a918cd..eb2264b 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/object/property-helper-devel.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/integration-api/adaptors/adaptor.h>
@@ -1290,6 +1291,7 @@ void TextEditor::RenderText( Text::Controller::UpdateTextType updateTextType )
          ++it )
     {
       self.Add( *it );
+      DevelActor::LowerToBottom( *it );
     }
     mClippingDecorationActors.clear();
 
index c7c9c4b..6083974 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/images/resource-image.h>
 #include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/integration-api/adaptors/adaptor.h>
 #include <dali/integration-api/debug.h>
@@ -1362,6 +1363,7 @@ void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
          ++it )
     {
       self.Add( *it );
+      DevelActor::LowerToBottom(*it);
     }
     mClippingDecorationActors.clear();
 
index fd1d8e4..020a5cb 100644 (file)
@@ -613,8 +613,9 @@ void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
           if( !isValidFont ) // (3)
           {
             // The given font has not been validated.
+            int validCharacterIndex = fontClient.GetGlyphIndex(cachedDefaultFontId, character );
 
-            if( isValidCachedDefaultFont )
+            if( isValidCachedDefaultFont && validCharacterIndex != 0u )
             {
               // Use the cached default font for the script if there is one.
               fontId = cachedDefaultFontId;
index d50cb91..e50edca 100644 (file)
@@ -62,6 +62,7 @@ const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
 const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
 const char * const IMAGE_ATLASING("atlasing");
+const char * const ALPHA_MASK_URL("alphaMaskUrl");
 
 // fitting modes
 DALI_ENUM_TO_STRING_TABLE_BEGIN( FITTING_MODE )
@@ -261,8 +262,10 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
   mPixelArea( FULL_TEXTURE_RECT ),
   mPlacementActor(),
   mImageUrl( imageUrl ),
+  mAlphaMaskUrl(),
   mDesiredSize( size ),
   mTextureId( TextureManager::INVALID_TEXTURE_ID ),
+  mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ),
   mFittingMode( fittingMode ),
   mSamplingMode( samplingMode ),
   mWrapModeU( WrapMode::DEFAULT ),
@@ -279,8 +282,10 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
   mPixelArea( FULL_TEXTURE_RECT ),
   mPlacementActor(),
   mImageUrl(),
+  mAlphaMaskUrl(),
   mDesiredSize(),
   mTextureId( TextureManager::INVALID_TEXTURE_ID ),
+  mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ),
   mFittingMode( FittingMode::DEFAULT ),
   mSamplingMode( SamplingMode::DEFAULT ),
   mWrapModeU( WrapMode::DEFAULT ),
@@ -292,6 +297,11 @@ ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
 
 ImageVisual::~ImageVisual()
 {
+  if( mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
+  {
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+    textureManager.Remove( mAlphaMaskId );
+  }
 }
 
 void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
@@ -342,9 +352,20 @@ void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
       {
         DoSetProperty( Toolkit::DevelImageVisual::Property::ATLASING, keyValue.second );
       }
+      else if ( keyValue.first == ALPHA_MASK_URL )
+      {
+        DoSetProperty( Toolkit::DevelImageVisual::Property::ALPHA_MASK_URL, keyValue.second );
+      }
     }
   }
 
+  if( mAlphaMaskUrl.IsValid() )
+  {
+    // Immediately trigger the alpha mask loading (it may just get a cached value)
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+    mAlphaMaskId = textureManager.RequestMaskLoad( mAlphaMaskUrl );
+  }
+
   if( ( mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING ) && mImageUrl.IsValid() )
   {
     // if sync loading is required, the loading should start
@@ -451,6 +472,15 @@ void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& v
       bool atlasing = false;
       mAttemptAtlasing = value.Get( atlasing );
     }
+
+    case Toolkit::DevelImageVisual::Property::ALPHA_MASK_URL:
+    {
+      std::string alphaUrl;
+      if( value.Get( alphaUrl ) )
+      {
+        mAlphaMaskUrl = VisualUrl( alphaUrl );
+      }
+    }
   }
 }
 
@@ -522,7 +552,10 @@ void ImageVisual::CreateRenderer( TextureSet& textureSet )
     }
   }
 
-  shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_ON ); // Set default to align
+  // Set pixel align off as default.
+  // ToDo: Pixel align causes issues such as rattling image animation.
+  // We should trun it off until issues are resolved
+  shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
 
   mImpl->mRenderer = Renderer::New( geometry, shader );
   if( textureSet )
@@ -651,8 +684,17 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronous
     {
       mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
       TextureManager& textureManager = mFactoryCache.GetTextureManager();
-      mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
-                                               mSamplingMode, TextureManager::NO_ATLAS, this );
+      if( mAlphaMaskId == TextureManager::INVALID_TEXTURE_ID )
+      {
+        mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
+                                                 mSamplingMode, TextureManager::NO_ATLAS, this );
+      }
+      else
+      {
+        mTextureId = textureManager.RequestLoad( mImageUrl, mAlphaMaskId, mDesiredSize,
+                                                 mFittingMode, mSamplingMode,
+                                                 TextureManager::NO_ATLAS, this );
+      }
 
       TextureManager::LoadState loadState = textureManager.GetTextureState( mTextureId );
 
@@ -819,6 +861,7 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
 
   map.Insert( Toolkit::DevelImageVisual::Property::ATLASING, mAttemptAtlasing );
+  map.Insert( Toolkit::DevelImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl.GetUrl() );
 }
 
 void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
index 9113437..31dc79f 100644 (file)
@@ -46,13 +46,14 @@ class ImageVisual;
 typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
 
 /**
- * The visual which renders an image to the control's quad
+ * The visual which renders an image to a quad geometry
  *
  * The following properties are optional
  *
  * | %Property Name     | Type              |
  * |--------------------|-------------------|
  * | url                | STRING            |
+ * | alphaMaskUrl       | STRING            |
  * | fittingMode        | INTEGER OR STRING |
  * | samplingMode       | INTEGER OR STRING |
  * | desiredWidth       | INTEGER           |
@@ -319,9 +320,11 @@ private:
   Vector4 mPixelArea;
   WeakHandle<Actor> mPlacementActor;
   VisualUrl mImageUrl;
+  VisualUrl mAlphaMaskUrl;
 
   Dali::ImageDimensions mDesiredSize;
   TextureManager::TextureId mTextureId;
+  TextureManager::TextureId mAlphaMaskId;
 
   Dali::FittingMode::Type mFittingMode:3;
   Dali::SamplingMode::Type mSamplingMode:4;
index 7c8098d..2283f22 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL HEADERS
 #include <dali/devel-api/common/hash.h>
+#include <dali/devel-api/images/pixel-data-mask.h>
 #include <dali/devel-api/images/texture-set-image.h>
 #include <dali/integration-api/debug.h>
 
@@ -29,6 +30,7 @@
 #include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
 
+
 namespace Dali
 {
 
@@ -71,13 +73,46 @@ TextureManager::TextureId TextureManager::RequestLoad(
   const UseAtlas           useAtlas,
   TextureUploadObserver*   observer )
 {
+  return RequestInternalLoad( url, INVALID_TEXTURE_ID, desiredSize, fittingMode, samplingMode, useAtlas, GPU_UPLOAD, observer );
+}
+
+TextureManager::TextureId TextureManager::RequestLoad(
+  const VisualUrl&         url,
+  TextureId                maskTextureId,
+  const ImageDimensions    desiredSize,
+  FittingMode::Type        fittingMode,
+  Dali::SamplingMode::Type samplingMode,
+  const UseAtlas           useAtlas,
+  TextureUploadObserver*   observer )
+{
+  return RequestInternalLoad( url, maskTextureId, desiredSize, fittingMode, samplingMode, useAtlas, GPU_UPLOAD, observer );
+}
+
+TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
+{
+  // Use the normal load procedure to get the alpha mask.
+  return RequestInternalLoad( maskUrl, INVALID_TEXTURE_ID, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, CPU, NULL );
+}
+
+
+TextureManager::TextureId TextureManager::RequestInternalLoad(
+  const VisualUrl&         url,
+  TextureId                maskTextureId,
+  const ImageDimensions    desiredSize,
+  FittingMode::Type        fittingMode,
+  Dali::SamplingMode::Type samplingMode,
+  UseAtlas                 useAtlas,
+  StorageType              storageType,
+  TextureUploadObserver*   observer )
+{
   // First check if the requested Texture is cached.
-  const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas );
+  const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId );
 
-  // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
-  int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas );
   TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
 
+  // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
+  int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId );
+
   // Check if the requested Texture exists in the cache.
   if( cacheIndex != INVALID_CACHE_INDEX )
   {
@@ -87,19 +122,25 @@ TextureManager::TextureId TextureManager::RequestLoad(
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture @%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
   }
-  else
+
+  if( textureId == INVALID_TEXTURE_ID ) // There was no caching, or caching not required
   {
     // We need a new Texture.
     textureId = GenerateUniqueTextureId();
-    mTextureInfoContainer.push_back( TextureInfo( textureId, url.GetUrl(), desiredSize, fittingMode, samplingMode, false, useAtlas, textureHash ) );
+    mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(),
+                                                  desiredSize, fittingMode, samplingMode,
+                                                  false, useAtlas, textureHash ) );
     cacheIndex = mTextureInfoContainer.size() - 1u;
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId );
   }
 
   // The below code path is common whether we are using the cache or not.
-  // The textureInfoIndex now refers to either a pre-existing cached TextureInfo, or a new TextureInfo just created.
+  // The textureInfoIndex now refers to either a pre-existing cached TextureInfo,
+  // or a new TextureInfo just created.
   TextureInfo& textureInfo( mTextureInfoContainer[ cacheIndex ] );
+  textureInfo.maskTextureId = maskTextureId;
+  textureInfo.storageType = storageType;
 
   DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureInfo loadState:%s\n",
                  textureInfo.loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" :
@@ -127,7 +168,7 @@ TextureManager::TextureId TextureManager::RequestLoad(
       {
         // The Texture has already loaded. The other observers have already been notified.
         // We need to send a "late" loaded notification for this observer.
-        observer->UploadComplete( textureInfo.loadingSucceeded,
+        observer->UploadComplete( true,
                                   textureInfo.textureSet, textureInfo.useAtlas,
                                   textureInfo.atlasRect );
       }
@@ -141,6 +182,11 @@ TextureManager::TextureId TextureManager::RequestLoad(
       ObserveTexture( textureInfo, observer );
       break;
     }
+    case TextureManager::LOAD_FINISHED:
+    case TextureManager::WAITING_FOR_MASK:
+    case TextureManager::LOAD_FAILED:
+      // Loading has already completed. Do nothing.
+      break;
   }
 
   // Return the TextureId for which this Texture can now be referenced by externally.
@@ -226,8 +272,6 @@ TextureSet TextureManager::GetTextureSet( TextureId textureId )
   return textureSet;
 }
 
-
-
 bool TextureManager::LoadTexture( TextureInfo& textureInfo )
 {
   bool success = true;
@@ -241,16 +285,18 @@ bool TextureManager::LoadTexture( TextureInfo& textureInfo )
       if( textureInfo.url.IsLocal() )
       {
         mAsyncLocalLoadingInfoContainer.push_back( AsyncLoadingInfo( textureInfo.textureId ) );
-        mAsyncLocalLoadingInfoContainer.back().loadId = GetImplementation(mAsyncLocalLoader).Load(
-          textureInfo.url, textureInfo.desiredSize,
-          textureInfo.fittingMode, textureInfo.samplingMode, true );
+        mAsyncLocalLoadingInfoContainer.back().loadId =
+          GetImplementation(mAsyncLocalLoader).Load( textureInfo.url, textureInfo.desiredSize,
+                                                     textureInfo.fittingMode,
+                                                     textureInfo.samplingMode, true );
       }
       else
       {
         mAsyncRemoteLoadingInfoContainer.push_back( AsyncLoadingInfo( textureInfo.textureId ) );
-        mAsyncRemoteLoadingInfoContainer.back().loadId = GetImplementation(mAsyncRemoteLoader).Load(
-          textureInfo.url, textureInfo.desiredSize,
-          textureInfo.fittingMode, textureInfo.samplingMode, true );
+        mAsyncRemoteLoadingInfoContainer.back().loadId =
+          GetImplementation(mAsyncRemoteLoader).Load( textureInfo.url, textureInfo.desiredSize,
+                                                      textureInfo.fittingMode,
+                                                      textureInfo.samplingMode, true );
       }
     }
   }
@@ -291,15 +337,13 @@ void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingCo
       int cacheIndex = GetCacheIndexFromId( loadingInfo.textureId );
       if( cacheIndex != INVALID_CACHE_INDEX )
       {
-        // Once we have found the TextureInfo data, we call a common function used to process loaded data for both sync and async loads.
         TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
 
         DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  CacheIndex:%d LoadState: %d\n", cacheIndex, textureInfo.loadState );
 
-        // Only perform atlasing if the load has not been cancelled since the request.
         if( textureInfo.loadState != CANCELLED )
         {
-          // Perform atlasing and finalize the load.
+          // textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified)
           PostLoad( textureInfo, pixelData );
         }
         else
@@ -313,37 +357,108 @@ void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingCo
   }
 }
 
-
-bool TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
+void TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
 {
-  bool success = false;
-
   // Was the load successful?
   if( pixelData && ( pixelData.GetWidth() != 0 ) && ( pixelData.GetHeight() != 0 ) )
   {
-    // Regardless of whether the atlasing succeeds or not, we have a valid image, so we mark it as successful.
-    success = true;
-
-    bool usingAtlas = false;
-
     // No atlas support for now
     textureInfo.useAtlas = NO_ATLAS;
 
-    if( ! usingAtlas )
+    if( textureInfo.storageType == GPU_UPLOAD )
     {
-      DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  TextureManager::PostLoad() textureId:%d\n", textureInfo.textureId );
+      // If there is a mask texture ID associated with this texture, then apply the mask
+      // if it's already loaded. If it hasn't, and the mask is still loading,
+      // wait for the mask to finish loading.
+      if( textureInfo.maskTextureId != INVALID_TEXTURE_ID )
+      {
+        LoadState maskLoadState = GetTextureState( textureInfo.maskTextureId );
+        if( maskLoadState == LOADING )
+        {
+          textureInfo.pixelData = pixelData; // Store the pixel data temporarily
+          textureInfo.loadState = WAITING_FOR_MASK;
+        }
+        else if( maskLoadState == LOAD_FINISHED )
+        {
+          ApplyMask( pixelData, textureInfo.maskTextureId );
+          UploadTexture( pixelData, textureInfo );
+          NotifyObservers( textureInfo, true );
+        }
+      }
+      else
+      {
+        UploadTexture( pixelData, textureInfo );
+        NotifyObservers( textureInfo, true );
+      }
+    }
+    else // currently, CPU textures are local to texture manager
+    {
+      textureInfo.pixelData = pixelData; // Store the pixel data
+      textureInfo.loadState = LOAD_FINISHED;
 
-      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
-      texture.Upload( pixelData );
-      textureInfo.textureSet = TextureSet::New();
-      textureInfo.textureSet.SetTexture( 0u, texture );
+      // Check if there was another texture waiting for this load to complete
+      // (e.g. if this was an image mask, and its load is on a different thread)
+      CheckForWaitingTexture( textureInfo );
     }
   }
-
-  if( ! success )
+  else
   {
     DALI_LOG_ERROR( "TextureManager::AsyncImageLoad(%s) failed\n", textureInfo.url.GetUrl().c_str() );
     // @todo If the load was unsuccessful, upload the broken image.
+    textureInfo.loadState = LOAD_FAILED;
+    CheckForWaitingTexture( textureInfo );
+    NotifyObservers( textureInfo, false );
+  }
+}
+
+void TextureManager::CheckForWaitingTexture( TextureInfo& maskTextureInfo )
+{
+  // Search the cache, checking if any texture has this texture id as a
+  // maskTextureId:
+  const unsigned int size = mTextureInfoContainer.size();
+
+  for( unsigned int cacheIndex = 0; cacheIndex < size; ++cacheIndex )
+  {
+    if( mTextureInfoContainer[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
+        mTextureInfoContainer[cacheIndex].loadState == WAITING_FOR_MASK )
+    {
+      TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
+      PixelData pixelData = textureInfo.pixelData;
+      textureInfo.pixelData.Reset();
+
+      if( maskTextureInfo.loadState == LOAD_FINISHED )
+      {
+        ApplyMask( pixelData, maskTextureInfo.textureId );
+        UploadTexture( pixelData, textureInfo );
+        NotifyObservers( textureInfo, true );
+      }
+      else
+      {
+        DALI_LOG_ERROR( "TextureManager::ApplyMask to %s failed\n", textureInfo.url.GetUrl().c_str() );
+        textureInfo.loadState = LOAD_FAILED;
+        NotifyObservers( textureInfo, false );
+      }
+    }
+  }
+}
+
+void TextureManager::ApplyMask( PixelData pixelData, TextureId maskTextureId )
+{
+  int maskCacheIndex = GetCacheIndexFromId( maskTextureId );
+  PixelData maskPixelData = mTextureInfoContainer[maskCacheIndex].pixelData;
+  Dali::ApplyMask( pixelData, maskPixelData );
+}
+
+void TextureManager::UploadTexture( PixelData pixelData, TextureInfo& textureInfo )
+{
+  if( textureInfo.useAtlas != USE_ATLAS )
+  {
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId );
+
+    Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
+    texture.Upload( pixelData );
+    textureInfo.textureSet = TextureSet::New();
+    textureInfo.textureSet.SetTexture( 0u, texture );
   }
 
   // Update the load state.
@@ -351,28 +466,62 @@ bool TextureManager::PostLoad( TextureInfo& textureInfo, PixelData pixelData )
   // load attempt is in progress or not.  If unsuccessful, a broken
   // image is still loaded.
   textureInfo.loadState = UPLOADED;
+}
 
-  // We need to store the load succeeded state as if a future request to load this texture comes in,
-  // we need to re-broadcast the UploadComplete notification to that observer.
-  textureInfo.loadingSucceeded = success;
+void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
+{
+  TextureId textureId = textureInfo.textureId;
 
   // If there is an observer: Notify the load is complete, whether successful or not:
-  const unsigned int observerCount = textureInfo.observerList.Count();
-  for( unsigned int i = 0; i < observerCount; ++i )
+  // And erase it from the list
+  unsigned int observerCount = textureInfo.observerList.Count();
+  TextureInfo* info = &textureInfo;
+
+  while( observerCount )
   {
-    TextureUploadObserver* observer = textureInfo.observerList[i];
-    if( observer )
+    TextureUploadObserver* observer = info->observerList[0];
+
+    // During UploadComplete() a Control ResourceReady() signal is emitted
+    // During that signal the app may add remove /add Textures (e.g. via ImageViews).
+    // At this point no more observers can be added to the observerList, because  textureInfo.loadState = UPLOADED
+    // However it is possible for observers to be removed, hence we check the observer list count every iteration
+
+    // Also the reference to the textureInfo struct can become invalidated, because new load requests can modify
+    // the mTextureInfoContainer list (e.g. if more requests are pushed_back it can cause the list to be resized
+    // invalidating the reference to the TextureInfo ).
+    observer->UploadComplete( success, info->textureSet, info->useAtlas, info->atlasRect );
+    observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
+
+    // regrab the textureInfo from the container as it may have been invalidated, if textures have been removed
+    // or added during the ResourceReady() signal emission (from UploadComplete() )
+    int textureInfoIndex = GetCacheIndexFromId( textureId );
+
+    if( textureInfoIndex == INVALID_CACHE_INDEX)
     {
-      observer->UploadComplete( success, textureInfo.textureSet, textureInfo.useAtlas, textureInfo.atlasRect );
-      observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
+      // texture has been removed
+      return;
+    }
+    info = &mTextureInfoContainer[ textureInfoIndex ];
+    observerCount = info->observerList.Count();
+    if ( observerCount > 0 )
+    {
+      // remove the observer that was just triggered if it's still in the list
+      for( TextureInfo::ObserverListType::Iterator j = info->observerList.Begin(); j != info->observerList.End(); ++j )
+      {
+        if( *j == observer )
+        {
+          info->observerList.Erase( j );
+          observerCount--;
+          break;
+         }
+      }
     }
-  }
 
-  textureInfo.observerList.Clear();
+  }
 
-  return success;
 }
 
+
 TextureManager::TextureId TextureManager::GenerateUniqueTextureId()
 {
   return mCurrentTextureId++;
@@ -399,7 +548,8 @@ TextureManager::TextureHash TextureManager::GenerateHash(
   const ImageDimensions          size,
   const FittingMode::Type        fittingMode,
   const Dali::SamplingMode::Type samplingMode,
-  const UseAtlas                 useAtlas )
+  const UseAtlas                 useAtlas,
+  TextureId                      maskTextureId )
 {
   std::string hashTarget( url );
   const size_t urlLength = hashTarget.length();
@@ -431,6 +581,20 @@ TextureManager::TextureHash TextureManager::GenerateHash(
     hashTarget[ urlLength ] = useAtlas;
   }
 
+  if( maskTextureId != INVALID_TEXTURE_ID )
+  {
+    hashTarget.resize( urlLength + sizeof( TextureId ) );
+    TextureId* hashTargetPtr = reinterpret_cast<TextureId*>(&( hashTarget[ urlLength ] ));
+
+    // Append the hash target to the end of the URL byte by byte:
+    // (to avoid SIGBUS / alignment issues)
+    for( size_t byteIter = 0; byteIter < sizeof( TextureId ); ++byteIter )
+    {
+      *hashTargetPtr++ = maskTextureId & 0xff;
+      maskTextureId >>= 8u;
+    }
+  }
+
   return Dali::CalculateHash( hashTarget );
 }
 
@@ -440,7 +604,8 @@ int TextureManager::FindCachedTexture(
   const ImageDimensions             size,
   const FittingMode::Type           fittingMode,
   const Dali::SamplingMode::Type    samplingMode,
-  const bool                        useAtlas )
+  const bool                        useAtlas,
+  TextureId                         maskTextureId)
 {
   // Default to an invalid ID, in case we do not find a match.
   int cacheIndex = INVALID_CACHE_INDEX;
@@ -456,6 +621,7 @@ int TextureManager::FindCachedTexture(
 
       if( ( url == textureInfo.url.GetUrl() ) &&
           ( useAtlas == textureInfo.useAtlas ) &&
+          ( maskTextureId == textureInfo.maskTextureId ) &&
           ( size == textureInfo.desiredSize ) &&
           ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
             ( fittingMode == textureInfo.fittingMode &&
index 312b12e..a650384 100644 (file)
@@ -41,6 +41,8 @@ namespace Toolkit
 namespace Internal
 {
 
+class MaskTextureObserver;
+
 /**
  * The TextureManager provides a common Image loading API for Visuals.
  *
@@ -55,12 +57,27 @@ public:
   typedef int32_t TextureId;       ///< The TextureId type. This is used as a handle to refer to a particular Texture.
   static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
 
+  /**
+   * Whether the texture should be atlased or uploaded into it's own GPU texture
+   */
   enum UseAtlas
   {
     NO_ATLAS,
     USE_ATLAS
   };
 
+  /**
+   * Whether the texture should be stored in CPU memory, or uploaded to a GPU texture
+   */
+  enum StorageType
+  {
+    CPU,
+    GPU_UPLOAD
+  };
+
+  /**
+   * Whether the texture should be loaded synchronously or asynchronously.
+   */
   enum LoadType
   {
     LOAD_ASYNCHRONOUSLY,
@@ -68,14 +85,17 @@ public:
   };
 
   /**
-   * @brief The LoadState Enumeration represents the current state of a particular Textures life-cycle.
+   * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
    */
   enum LoadState
   {
     NOT_STARTED,     ///< Default
     LOADING,         ///< Loading has been started, but not finished.
-    UPLOADED,        ///< Loaded (and ready).
+    LOAD_FINISHED,   ///< Loading has finished. (for CPU storage only)
+    WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
+    UPLOADED,        ///< Uploaded and ready. (For GPU upload only)
     CANCELLED,       ///< Removed before loading completed
+    LOAD_FAILED      ///< Async loading failed, e.g. connection problem
   };
 
 public:
@@ -91,7 +111,7 @@ public:
   ~TextureManager();
 
 
-// TextureManager Main API:
+  // TextureManager Main API:
 
   /**
    * @brief Requests an image load of the given URL.
@@ -119,6 +139,40 @@ public:
                          TextureUploadObserver*   observer );
 
   /**
+   * @brief Requests an image load of the given URL, when the texture has
+   * have loaded, it will perform a CPU blend with the image mask, and upload
+   * the blend texture.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url               The URL of the image to load
+   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode       The FittingMode to use
+   * @param[in] samplingMode      The SamplingMode to use
+   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                              This is called when an image load completes (or fails).
+   * @return                      A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestLoad( const VisualUrl&         url,
+                         TextureId                maskTextureId,
+                         const ImageDimensions    desiredSize,
+                         FittingMode::Type        fittingMode,
+                         Dali::SamplingMode::Type samplingMode,
+                         const UseAtlas           useAtlasing,
+                         TextureUploadObserver*   observer );
+
+  /**
+   * Requests a masking image to be loaded. This mask is not uploaded to GL,
+   * instead, it is stored in CPU memory, and can be used for CPU blending.
+   */
+  TextureId RequestMaskLoad( const VisualUrl& maskUrl );
+
+  /**
    * @brief Remove a Texture from the TextureManager.
    *
    * Textures are cached and therefore only the removal of the last
@@ -145,16 +199,48 @@ public:
 
 private:
 
+  /**
+   * @brief Requests an image load of the given URL, when the texture has
+   * have loaded, if there is a valid maskTextureId, it will perform a
+   * CPU blend with the mask, and upload the blend texture.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url               The URL of the image to load
+   * @param[in] maskTextureId     The texture id of an image to use as a mask. If no mask is required, then set to INVALID_TEXTURE_ID
+   * @param[in] desiredSize       The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode       The FittingMode to use
+   * @param[in] samplingMode      The SamplingMode to use
+   * @param[in] useAtlasing       Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                              but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] storageType,      Whether the pixel data is stored in the cache or uploaded to the GPU
+   * @param[in] observer          The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                              This is called when an image load completes (or fails).
+   * @return                      A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestInternalLoad(
+    const VisualUrl&         url,
+    TextureId                maskTextureId,
+    const ImageDimensions    desiredSize,
+    FittingMode::Type        fittingMode,
+    Dali::SamplingMode::Type samplingMode,
+    UseAtlas                 useAtlas,
+    StorageType              storageType,
+    TextureUploadObserver*   observer );
+
 
   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
 
   /**
    * @brief This struct is used to manage the life-cycle of Texture loading and caching.
-   * TODO-TX: pimpl this
    */
   struct TextureInfo
   {
     TextureInfo( TextureId textureId,
+                 TextureId maskTextureId,
                  const VisualUrl& url,
                  ImageDimensions desiredSize,
                  FittingMode::Type fittingMode,
@@ -167,14 +253,15 @@ private:
       useSize( desiredSize ),
       atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
       textureId( textureId ),
+      maskTextureId( maskTextureId ),
       hash( hash ),
       referenceCount( 1u ),
       loadState( NOT_STARTED ),
       fittingMode( fittingMode ),
       samplingMode( samplingMode ),
+      storageType( GPU_UPLOAD ),
       loadSynchronously( loadSynchronously ),
-      useAtlas( useAtlas ),
-      loadingSucceeded( false )
+      useAtlas( useAtlas )
     {
     }
 
@@ -185,21 +272,22 @@ private:
 
     ObserverListType observerList; ///< Container used to store all observer clients of this Texture
     Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
-    PixelData pixelData;           ///< The PixelData holding the image data (this is used if atlasing is deferred)
+    PixelData pixelData;           ///< The PixelData holding the image data (this is used if atlasing is deferred or CPU storage is required)
     TextureSet textureSet;         ///< The TextureSet holding the Texture
     VisualUrl url;                 ///< The URL of the image
     ImageDimensions desiredSize;   ///< The size requested
     ImageDimensions useSize;       ///< The size used
     Vector4 atlasRect;             ///< The atlas rect used if atlased
     TextureId textureId;           ///< The TextureId associated with this Texture
+    TextureId maskTextureId;       ///< The mask TextureId to be applied on load
     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
     int16_t referenceCount;        ///< The reference count of clients using this Texture
     LoadState loadState:3;         ///< The load state showing the load progress of the Texture
     FittingMode::Type fittingMode:2; ///< The requested FittingMode
     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
-    bool loadSynchronously;        ///< True if synchronous loading was requested
-    UseAtlas useAtlas; ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
-    bool loadingSucceeded;         ///< True if the image was loaded successfully
+    StorageType storageType:1;     ///< CPU storage / GPU upload;
+    bool loadSynchronously:1;      ///< True if synchronous loading was requested
+    UseAtlas useAtlas:1;           ///< USE_ATLAS if an atlas was requested. This is updated to false if atlas is not used
   };
 
   // Structs:
@@ -279,11 +367,47 @@ private:
 
   /**
    * @brief Performs Post-Load steps including atlasing.
-   * @param[in]           textureInfo The struct associated with this Texture
-   * @param[in]           pixelData   The image pixelData
-   * @return                          True if successful
+   * @param[in] textureInfo The struct associated with this Texture
+   * @param[in] pixelData   The image pixelData
+   * @return    True if successful
    */
-  bool PostLoad( TextureManager::TextureInfo& textureInfo, PixelData pixelData );
+  void PostLoad( TextureManager::TextureInfo& textureInfo, PixelData pixelData );
+
+  /**
+   * Check if there is a texture waiting to be masked. If there
+   * is then apply this mask and upload it.
+   * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
+   */
+  void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
+
+  /**
+   * Apply the mask texture to the image texture.
+   * @param[in] pixelData The image pixelData to apply the mask to
+   * @param[in] maskTextureId The texture id of the mask.
+   */
+  void ApplyMask( PixelData pixelData, TextureId maskTextureId );
+
+  /**
+   * Upload the texture specified in pixelData to the appropriate location
+   * @param[in] pixelData The image data to upload
+   * @param[in] textureInfo The texture info containing the location to
+   * store the data to.
+   */
+  void UploadTexture( PixelData pixelData, TextureInfo& textureInfo );
+
+  /**
+   * Mark the texture as complete, and inform observers
+   * @param[in] textureInfo The struct associated with this Texture
+   */
+  void UploadComplete( TextureInfo& textureInfo );
+
+  /**
+   * Notify the current observers that the texture upload is complete,
+   * then remove the observers from the list.
+   * @param[in] textureInfo The struct associated with this Texture
+   * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
+   */
+  void NotifyObservers( TextureInfo& textureInfo, bool success );
 
   /**
    * @brief Generates a new, unique TextureId
@@ -301,30 +425,42 @@ private:
 
   /**
    * @brief Generates a hash for caching based on the input parameters.
+   * Only applies size, fitting mode andsampling mode if the size is specified.
+   * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
+   * Always applies useAtlas.
    * @param[in] url          The URL of the image to load
    * @param[in] size         The image size
    * @param[in] fittingMode  The FittingMode to use
    * @param[in] samplingMode The SamplingMode to use
    * @param[in] useAtlas     True if atlased
+   * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
    * @return                 A hash of the provided data for caching.
    */
   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
                             const FittingMode::Type fittingMode,
-                            const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas );
+                            const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
+                            TextureId maskTextureId );
 
   /**
    * @brief Looks up a cached texture by its hash.
    * If found, the given parameters are used to check there is no hash-collision.
-   * @param[in] hash The hash to look up
-   * @param[in] url          The URL of the image to load
-   * @param[in] size         The image size
-   * @param[in] fittingMode  The FittingMode to use
-   * @param[in] samplingMode The SamplingMode to use
-   * @param[in] useAtlas     True if atlased
-   * @return                 A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
+   * @param[in] hash          The hash to look up
+   * @param[in] url           The URL of the image to load
+   * @param[in] size          The image size
+   * @param[in] fittingMode   The FittingMode to use
+   * @param[in] samplingMode  The SamplingMode to use
+   * @param[in] useAtlas      True if atlased
+   * @param[in] maskTextureId Optional texture ID to use to mask this image
+   * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
    */
-  TextureManager::TextureId FindCachedTexture( const TextureManager::TextureHash hash, const std::string& url, const ImageDimensions size,
-      const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const bool useAtlas );
+  TextureManager::TextureId FindCachedTexture(
+    const TextureManager::TextureHash hash,
+    const std::string& url,
+    const ImageDimensions size,
+    const FittingMode::Type fittingMode,
+    const Dali::SamplingMode::Type samplingMode,
+    const bool useAtlas,
+    TextureId maskTextureId );
 
 
 private:
index 0dfc002..59e0a18 100644 (file)
@@ -122,6 +122,7 @@ Vector4 Control::GetBackgroundColor() const
 void Control::SetBackground( const Property::Map& map )
 {
   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
+  visual.SetName("background");
   if( visual )
   {
     mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
index d2ad3a6..fca2eab 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 43;
+const unsigned int TOOLKIT_MICRO_VERSION = 44;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 8db8b94..13a5fb8 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.2.43
+Version:    1.2.44
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT