[dali_1.3.6] Merge branch 'devel/master' 73/166073/1
authorRichard Huang <r.huang@samsung.com>
Fri, 5 Jan 2018 13:33:40 +0000 (13:33 +0000)
committerRichard Huang <r.huang@samsung.com>
Fri, 5 Jan 2018 13:33:40 +0000 (13:33 +0000)
Change-Id: I8cfcb274c8cf93ac21e0d432733caaaa3e6e4c9a

52 files changed:
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Typesetter.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/visual-factory/visual-factory.cpp
dali-toolkit/devel-api/visual-factory/visual-factory.h
dali-toolkit/devel-api/visuals/color-visual-properties-devel.h [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/text/cursor-helper-functions.cpp
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/text-typesetter.h
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-scroller.cpp
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h
dali-toolkit/internal/visuals/animated-image/image-cache.cpp
dali-toolkit/internal/visuals/animated-image/image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
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/image/image-visual.h
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h
dali-toolkit/internal/visuals/texture-upload-observer.h
dali-toolkit/internal/visuals/visual-base-impl.cpp [changed mode: 0644->0755]
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-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/internal/visuals/visual-url.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index d792609..bd88e76 100644 (file)
@@ -28,13 +28,11 @@ namespace Toolkit
 namespace Internal
 {
 
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
-
 DummyVisualPtr DummyVisual::New( const Property::Map& properties )
 {
-  VisualFactoryCachePtr factoryCache = new VisualFactoryCache;
+  VisualFactoryCache* factoryCache = new VisualFactoryCache(false);
 
-  DummyVisualPtr dummyVisualPtr( new DummyVisual( *( factoryCache.Get() ) ) );
+  DummyVisualPtr dummyVisualPtr( new DummyVisual( *factoryCache ) );
 
   return dummyVisualPtr;
 }
index 14f352c..44136a7 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali-toolkit/internal/text/rendering/text-typesetter.h>
 #include <dali-toolkit/internal/text/rendering/view-model.h>
 #include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -108,7 +109,7 @@ int UtcDaliTextRenderingControllerRender(void)
   DALI_TEST_CHECK( renderingController );
 
   // Renders the text and creates the final bitmap.
-  PixelData bitmap = renderingController->Render( relayoutSize );
+  PixelData bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
   DALI_TEST_CHECK( bitmap );
 
   DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
@@ -120,7 +121,7 @@ int UtcDaliTextRenderingControllerRender(void)
   controller->Relayout( relayoutSize );
 
   // Renders the text and creates the final bitmap.
-  bitmap = renderingController->Render( relayoutSize );
+  bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
   DALI_TEST_CHECK( bitmap );
 
   DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
@@ -131,7 +132,7 @@ int UtcDaliTextRenderingControllerRender(void)
   controller->Relayout( relayoutSize );
 
   // Renders the text and creates the final bitmap.
-  bitmap = renderingController->Render( relayoutSize );
+  bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
   DALI_TEST_CHECK( bitmap );
 
   DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
@@ -166,32 +167,32 @@ int UtcDaliTextTypesetterVerticalLineAlignment(void)
   DALI_TEST_CHECK( renderingController );
 
   {
-    controller->SetVerticalLineAlignment(Dali::Toolkit::DevelText::VerticalLineAlignment::TOP);
-    controller->Relayout(relayoutSize);
+    controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::TOP );
+    controller->Relayout( relayoutSize );
 
     // Renders the text and creates the final bitmap.
-    auto bitmap = renderingController->Render(relayoutSize);
+    auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
     DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
   }
 
   {
-    controller->SetVerticalLineAlignment(Dali::Toolkit::DevelText::VerticalLineAlignment::MIDDLE);
-    controller->Relayout(relayoutSize);
+    controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::MIDDLE );
+    controller->Relayout( relayoutSize );
 
     // Renders the text and creates the final bitmap.
-    auto bitmap = renderingController->Render(relayoutSize);
+    auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
     DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
   }
 
   {
-    controller->SetVerticalLineAlignment(Dali::Toolkit::DevelText::VerticalLineAlignment::BOTTOM);
-    controller->Relayout(relayoutSize);
+    controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::BOTTOM );
+    controller->Relayout( relayoutSize );
 
     // Renders the text and creates the final bitmap.
-    auto bitmap = renderingController->Render(relayoutSize);
+    auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
     DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
   }
 
   tet_result(TET_PASS);
   END_TEST;
-}
\ No newline at end of file
+}
index e09dd06..ebada51 100644 (file)
@@ -34,7 +34,8 @@ public:
   {
   }
 
-  void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect )
+  virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet,
+                               bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override
   {
     mLoaded = loadSuccess;
     mObserverCalled = true;
@@ -53,7 +54,7 @@ int UtcTextureManagerRequestLoad(void)
 
   TestObserver observer;
   std::string filename("image.png");
-
+  auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
   TextureManager::TextureId textureId = textureManager.RequestLoad(
     filename,
     ImageDimensions(),
@@ -62,7 +63,8 @@ int UtcTextureManagerRequestLoad(void)
     TextureManager::NO_ATLAS,
     &observer,
     true,
-    TextureManager::ReloadPolicy::CACHED );
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
 
   const VisualUrl& url = textureManager.GetVisualUrl( textureId );
 
index 0a4dad2..df48a7d 100755 (executable)
@@ -75,6 +75,18 @@ static void TestKeyInputFocusCallback( Control control )
 const char* TEST_LARGE_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/tbcol.png";
 const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/gallery-small-1.jpg";
 
+Vector4 GetControlBackgroundColor( Control& control )
+{
+  Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+
+  Vector4 color;
+  resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get( color );
+
+  return color;
+}
+
 } // namespace
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -458,6 +470,80 @@ int UtcDaliControlBackgroundColor(void)
   END_TEST;
 }
 
+int UtcDaliControlBackgroundColorRendererCount(void)
+{
+  tet_infoline( "Test ensures we only create renderers when non-transparent color is requested or if we our clipping-mode is set to CLIP_CHILDREN" );
+
+  ToolkitTestApplication application;
+  Control control = Control::New();
+  Stage::GetCurrent().Add( control );
+
+  tet_infoline( "Set transparent, no renderers should be created" );
+  control.SetBackgroundColor( Color::TRANSPARENT );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+  tet_infoline( "Set transparent alpha with positive RGB values, no renderers should be created, but returned color should reflect what we set" );
+  const Vector4 alphaZero( 1.0f, 0.5f, 0.25f, 0.0f );
+  control.SetBackgroundColor( alphaZero );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), alphaZero, TEST_LOCATION );
+
+  tet_infoline( "Set semi transparent alpha with positive RGB values, 1 renderer should be created, but returned color should reflect what we set" );
+  const Vector4 semiTransparent( 1.0f, 0.75f, 0.5f, 0.5f );
+  control.SetBackgroundColor( semiTransparent );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), semiTransparent, TEST_LOCATION );
+
+  tet_infoline( "Set transparent, ensure no renderers are created" );
+  control.SetBackgroundColor( Color::TRANSPARENT );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  tet_infoline( "Set control to clip its children, a renderer should be created which will be transparent" );
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  tet_infoline( "Set a color, only 1 renderer should exist" );
+  control.SetBackgroundColor( Color::RED );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::RED, TEST_LOCATION );
+
+  tet_infoline( "Clear the background, no renderers" );
+  control.ClearBackground();
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+  tet_infoline( "Set control to clip its children again, a renderer should be created which will be transparent" );
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  tet_infoline( "Disable clipping, no renderers" );
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::DISABLED );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliControlBackgroundImage(void)
 {
   ToolkitTestApplication application;
index a2adf41..1a15ec6 100644 (file)
@@ -154,6 +154,7 @@ int UtcDaliImageVisualPropertyMap(void)
 
   VisualFactory factory = VisualFactory::Get();
   DALI_TEST_CHECK( factory );
+  factory.SetPreMultiplyOnLoad( true );
 
   Property::Map propertyMap;
   propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
@@ -171,6 +172,119 @@ int UtcDaliImageVisualPropertyMap(void)
 
   DummyControl actor = DummyControl::New();
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  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( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto renderer = actor.GetRendererAt(0);
+  auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  auto preMultipliedAlpha = renderer.GetProperty<float>( preMultipliedIndex );
+  auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_EQUALS( preMultipliedAlpha, 1.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualNoPremultipliedAlpha01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual without pre-multiplied alpha" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+  factory.SetPreMultiplyOnLoad( false );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  // 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 );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto renderer = actor.GetRendererAt(0);
+  auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  auto preMultipliedAlpha = renderer.GetProperty<bool>( preMultipliedIndex );
+  auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+  DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualNoPremultipliedAlpha02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with no alpha channel" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  // 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 );
@@ -186,6 +300,14 @@ int UtcDaliImageVisualPropertyMap(void)
   application.Render();
 
   DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto renderer = actor.GetRendererAt(0);
+  auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  auto preMultipliedAlpha = renderer.GetProperty<bool>( preMultipliedIndex );
+  auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+  DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
 
   DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
 
index 07f1cac..a8f2c9d 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/events/touch-event-integ.h>
 #include <dali/integration-api/events/pan-gesture-event.h>
 #include <dali/integration-api/events/long-press-gesture-event.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
@@ -1631,6 +1632,12 @@ int utcDaliTextFieldEvent01(void)
   application.SendNotification();
   application.Render();
 
+  // Pressing delete key should be fine even if there is no text in TextField.
+  application.ProcessEvent( GenerateKey( "Delete", "Delete", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
   // Now the text field has the focus, so it can handle the key events.
   application.ProcessEvent( GenerateKey( "a", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
   application.ProcessEvent( GenerateKey( "a", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
index cf36a87..825e7d4 100644 (file)
@@ -1234,11 +1234,21 @@ int UtcDaliToolkitTextlabelTextDirection(void)
   label.SetProperty( TextLabel::Property::POINT_SIZE, 20 );
   Stage::GetCurrent().Add( label );
 
+  // Test LTR text
   DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ), TEST_LOCATION );
 
+  // Test RTL text
   label.SetProperty( TextLabel::Property::TEXT, "ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
   DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
 
+  // Test RTL text starting with weak character
+  label.SetProperty( TextLabel::Property::TEXT, "()ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  // Test RTL text string with emoji and weak character
+  label.SetProperty( TextLabel::Property::TEXT, "\xF0\x9F\x98\x81 () ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
   END_TEST;
 }
 
index ab45fc0..bf54997 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/text-visual-properties-devel.h>
@@ -3392,3 +3393,53 @@ int UtcDaliRegisterVisualWithDepthIndex(void)
 
   END_TEST;
 }
+
+int UtcDaliColorVisualRenderIfTransparentProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Test the renderIfTransparent property of ColorVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::COLOR );
+  propertyMap.Insert( ColorVisual::Property::MIX_COLOR, Color::BLUE );
+
+  tet_infoline( "Check default value" );
+  {
+    Visual::Base testVisual = factory.CreateVisual( propertyMap );
+    Property::Map returnedMap;
+    testVisual.CreatePropertyMap( returnedMap );
+
+    Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+    DALI_TEST_CHECK( renderIfTransparentProperty );
+    DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
+  }
+
+  propertyMap.Insert( DevelColorVisual::Property::RENDER_IF_TRANSPARENT, true );
+
+  tet_infoline( "Ensure set to value required" );
+  {
+    Visual::Base testVisual = factory.CreateVisual( propertyMap );
+    Property::Map returnedMap;
+    testVisual.CreatePropertyMap( returnedMap );
+
+    Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+    DALI_TEST_CHECK( renderIfTransparentProperty );
+    DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), true, TEST_LOCATION );
+  }
+
+  propertyMap[ DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = Color::BLUE;
+
+  tet_infoline( "Ensure it returns default value if set to wrong type" );
+  {
+    Visual::Base testVisual = factory.CreateVisual( propertyMap );
+    Property::Map returnedMap;
+    testVisual.CreatePropertyMap( returnedMap );
+
+    Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+    DALI_TEST_CHECK( renderIfTransparentProperty );
+    DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
index 54a45a3..9556968 100644 (file)
@@ -1905,14 +1905,14 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual1: Request animated image visual with a gif url" );
 
-  VisualFactory factory = VisualFactory::Get();
-  Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
-  DALI_TEST_CHECK( visual );
-
   TestGlAbstraction& gl = application.GetGlAbstraction();
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
   DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
   dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
@@ -1924,54 +1924,34 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
 
   // renderer is added to actor
   DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
-  // test the uniforms which used to handle the atlas rect
-  // the four frames should be located inside atlas as follows: atlas size 100*100
-  // -------------
-  // |     |     |
-  // |  0  |  1  |
-  // -------------
-  // |     |     |
-  // |  2  |  3  |
-  // -------------
-
   Renderer renderer = actor.GetRendererAt( 0u );
   DALI_TEST_CHECK( renderer );
 
-  Property::Value atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 0.5f, 49.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
-
-  // waiting for the resource uploading
-  application.SendNotification();
-  application.Render();
-
-  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
 
   // Force the timer used by the animatedImageVisual to tick,
   Dali::Timer timer = Timer::New( 0 );
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
-  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 0.5f, 99.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
 
   // Force the timer used by the animatedImageVisual to tick,
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
-  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 50.5f, 49.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
 
   // Force the timer used by the animatedImageVisual to tick,
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
-  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 50.5f, 99.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
 
   // Test SetOffStage().
   actor.Unparent();
index 0bfd7d4..812668b 100644 (file)
@@ -91,9 +91,10 @@ devel_api_visual_factory_header_files = \
   $(devel_api_src_dir)/visual-factory/visual-base.h
 
 devel_api_visuals_header_files = \
+  $(devel_api_src_dir)/visuals/animated-gradient-visual-properties-devel.h \
+  $(devel_api_src_dir)/visuals/color-visual-properties-devel.h \
   $(devel_api_src_dir)/visuals/image-visual-properties-devel.h \
   $(devel_api_src_dir)/visuals/image-visual-actions-devel.h \
-  $(devel_api_src_dir)/visuals/animated-gradient-visual-properties-devel.h \
   $(devel_api_src_dir)/visuals/text-visual-properties-devel.h \
   $(devel_api_src_dir)/visuals/visual-properties-devel.h
 
index b91d79d..666a2a1 100644 (file)
@@ -109,6 +109,16 @@ Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimension
   return GetImplementation( *this ).CreateVisual( url, size );
 }
 
+void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply )
+{
+  GetImplementation( *this ).SetPreMultiplyOnLoad( preMultiply );
+}
+
+bool VisualFactory::GetPreMultiplyOnLoad() const
+{
+  return GetImplementation( *this ).GetPreMultiplyOnLoad();
+}
+
 } // namespace Toolkit
 
 } // namespace Dali
index 25c17cc..856360b 100644 (file)
@@ -117,6 +117,25 @@ public:
    */
   Visual::Base CreateVisual( const std::string& url, ImageDimensions size );
 
+  /**
+   * @brief Enable or disable premultiplying alpha in images and image visuals.
+   *
+   * The default is to enable pre-multiplication on load.
+   *
+   * Applications that have assets with pre-multiplied alpha already applied should turn this option off.
+   *
+   * @param[in] preMultiply True if loaded images for image visuals should have alpha multiplied into the color
+   * channels.
+   */
+  void SetPreMultiplyOnLoad( bool preMultiply );
+
+  /**
+   * @brief Get the setting for automatically pre-multiplying image visual images on load.
+   *
+   * @return True if loaded images have pre-multiplied alpha applied on load, false otherwise.
+   */
+  bool GetPreMultiplyOnLoad() const;
+
 private:
 
   explicit DALI_INTERNAL VisualFactory(Internal::VisualFactory *impl);
diff --git a/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h
new file mode 100644 (file)
index 0000000..4eb8b3a
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2017 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/visuals/color-visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+
+namespace DevelColorVisual
+{
+
+/**
+ * @brief Additional ColorVisual Properties.
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of additional properties belonging to the ColorVisual.
+ */
+enum
+{
+  MIX_COLOR = Toolkit::ColorVisual::Property::MIX_COLOR,
+
+  /**
+   * @brief Whether to render if the MIX_COLOR is transparent.
+   * @details Name "renderIfTransparent", type Property::BOOLEAN.
+   * @note Optional.
+   * @note By default it's false, i.e. ColorVisual will not render if the MIX_COLOR is transparent.
+   */
+  RENDER_IF_TRANSPARENT = MIX_COLOR + 1,
+};
+
+} // namespace Property
+
+} // namespace ColorVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
index 3f420b5..5eece25 100644 (file)
@@ -60,6 +60,19 @@ namespace Internal
 namespace
 {
   const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+
+  /**
+   * @brief How the text visual should be aligned vertically inside the control.
+   *
+   * 0.0f aligns the text to the top, 0.5f aligns the text to the center, 1.0f aligns the text to the bottom.
+   * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
+   */
+  const float VERTICAL_ALIGNMENT_TABLE[ Text::VerticalAlignment::BOTTOM + 1 ] =
+  {
+    0.0f,  // VerticalAlignment::TOP
+    0.5f,  // VerticalAlignment::CENTER
+    1.0f   // VerticalAlignment::BOTTOM
+  };
 }
 
 namespace
@@ -940,10 +953,29 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
       std::swap( padding.start, padding.end );
     }
 
+    // Calculate the size of the visual that can fit the text
+    Size layoutSize = mController->GetTextModel()->GetLayoutSize();
+    layoutSize.x = contentSize.x;
+
+    const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
+    if ( shadowOffset.y > Math::MACHINE_EPSILON_1 )
+    {
+      layoutSize.y += shadowOffset.y;
+    }
+
+    float outlineWidth = mController->GetTextModel()->GetOutlineWidth();
+    layoutSize.y += outlineWidth * 2.0f;
+    layoutSize.y = std::min( layoutSize.y, contentSize.y );
+
+    // Calculate the offset for vertical alignment only, as the layout engine will do the horizontal alignment.
+    Vector2 alignmentOffset;
+    alignmentOffset.x = 0.0f;
+    alignmentOffset.y = ( contentSize.y - layoutSize.y ) * VERTICAL_ALIGNMENT_TABLE[mController->GetVerticalAlignment()];
+
     Property::Map visualTransform;
-    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, contentSize )
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, layoutSize )
                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
-                   .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( padding.start, padding.top ) )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( padding.start, padding.top ) + alignmentOffset )
                    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
                    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
                    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
@@ -1003,7 +1035,7 @@ void TextLabel::SetUpAutoScrolling()
 
   Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
 
-  PixelData data = typesetter->Render( verifiedSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
+  PixelData data = typesetter->Render( verifiedSize, mController->GetTextDirection(), Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
   Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
                                   data.GetPixelFormat(),
                                   data.GetWidth(),
index b5c1aaf..a83612d 100755 (executable)
@@ -15,6 +15,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/visuals/animated-image/image-cache.cpp \
    $(toolkit_src_dir)/visuals/animated-image/fixed-image-cache.cpp \
    $(toolkit_src_dir)/visuals/animated-image/rolling-image-cache.cpp \
+   $(toolkit_src_dir)/visuals/animated-image/rolling-gif-image-cache.cpp \
    $(toolkit_src_dir)/visuals/border/border-visual.cpp \
    $(toolkit_src_dir)/visuals/color/color-visual.cpp \
    $(toolkit_src_dir)/visuals/gradient/gradient-visual.cpp \
index 91b6a40..f437b8d 100644 (file)
@@ -467,6 +467,13 @@ CharacterIndex GetClosestCursorIndex( VisualModelPtr visualModel,
 void GetCursorPosition( GetCursorPositionParameters& parameters,
                         CursorInfo& cursorInfo )
 {
+  const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
+  if( NULL == modelLines )
+  {
+    // Nothing to do.
+    return;
+  }
+
   // Whether the logical cursor position is at the end of the whole text.
   const bool isLastPosition = parameters.logicalModel->mText.Count() == parameters.logical;
 
@@ -476,8 +483,6 @@ void GetCursorPosition( GetCursorPositionParameters& parameters,
   // Whether the cursor is in the last position and the last position is a new paragraph character.
   const bool isLastNewParagraph = parameters.isMultiline && isLastPosition && TextAbstraction::IsNewParagraph( *( parameters.logicalModel->mText.Begin() + characterOfLine ) );
 
-  const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
-
   const LineIndex lineIndex = parameters.visualModel->GetLineOfCharacter( characterOfLine );
   const LineRun& line = *( modelLines + lineIndex );
 
@@ -665,7 +670,6 @@ void GetCursorPosition( GetCursorPositionParameters& parameters,
     // Set the primary cursor's height.
     cursorInfo.primaryCursorHeight = cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight;
 
-
     cursorInfo.glyphOffset = line.ascender - glyphMetrics.ascender;
     // Set the primary cursor's position.
     cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + glyphAdvance;
index 314bc63..901c477 100755 (executable)
@@ -267,7 +267,7 @@ ViewModel* Typesetter::GetViewModel()
   return mModel;
 }
 
-PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
+PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
 {
   // @todo. This initial implementation for a TextLabel has only one visible page.
 
@@ -277,8 +277,32 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   // Retrieves the layout size.
   const Size& layoutSize = mModel->GetLayoutSize();
 
+  const float outlineWidth = mModel->GetOutlineWidth();
+
+  // Set the offset for the horizontal alignment according to the text direction and outline width.
+  int penX = 0;
+
+  switch( mModel->GetHorizontalAlignment() )
+  {
+    case HorizontalAlignment::BEGIN:
+    {
+      // No offset to add.
+      break;
+    }
+    case HorizontalAlignment::CENTER:
+    {
+      penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth : outlineWidth;
+      break;
+    }
+    case HorizontalAlignment::END:
+    {
+      penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth * 2.0f : outlineWidth * 2.0f;
+      break;
+    }
+  }
+
   // Set the offset for the vertical alignment.
-  int penY = 0u;
+  int penY = 0;
 
   switch( mModel->GetVerticalAlignment() )
   {
@@ -340,7 +364,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   if( RENDER_MASK == behaviour )
   {
     // Generate the image buffer as an alpha mask for color glyphs.
-    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
   }
   else if( RENDER_NO_TEXT == behaviour )
   {
@@ -351,7 +375,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   else
   {
     // Generate the image buffer for the text with no style.
-    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs -1 );
+    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
   }
 
   if ( ( RENDER_NO_STYLES != behaviour ) && ( RENDER_MASK != behaviour ) )
@@ -362,7 +386,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
     if ( outlineWidth > Math::MACHINE_EPSILON_1 )
     {
       // Create the image buffer for outline
-      Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs -1 );
+      Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
 
       // Combine the two buffers
       imageBuffer = CombineImageBuffer( imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight );
@@ -375,7 +399,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
     if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
     {
       // Create the image buffer for shadow
-      Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+      Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
 
       // Check whether it will be a soft shadow
       const float& blurRadius = mModel->GetShadowBlurRadius();
@@ -394,7 +418,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
     if ( underlineEnabled )
     {
       // Create the image buffer for underline
-      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
 
       // Combine the two buffers
       imageBuffer = CombineImageBuffer( imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight );
@@ -407,7 +431,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   return pixelData;
 }
 
-Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
+Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
 {
   // Retrieve lines, glyphs, positions and colors from the view model.
   const Length modelNumberOfLines = mModel->GetNumberOfLines();
@@ -451,6 +475,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth
 
     // Sets the horizontal offset of the line.
     glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int>( line.alignmentOffset );
+    glyphData.horizontalOffset += horizontalOffset;
 
     // Increases the vertical offset with the line's ascender.
     glyphData.verticalOffset += static_cast<int>( line.ascender );
index 285348e..453541b 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/public-api/images/pixel-data.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 
 namespace Dali
 {
@@ -102,13 +103,14 @@ public:
    * - Combines different image buffers to create the pixel data used to generate the final image
    *
    * @param[in] size The renderer size.
+   * @param[in] textDirection The direction of the text.
    * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
    * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
    * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
    *
    * @return A pixel data with the text rendered.
    */
-  PixelData Render( const Vector2& size, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
+  PixelData Render( const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
 
 private:
   /**
@@ -137,13 +139,14 @@ private:
    * @param[in] style The style of the text.
    * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment, not ignored by default.
    * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+   * @param[in] horizontalOffset The horizontal offset to be added to the glyph's position.
    * @param[in] verticalOffset The vertical offset to be added to the glyph's position.
    * @param[in] fromGlyphIndex The index of the first glyph within the text to be drawn
    * @param[in] toGlyphIndex The index of the last glyph within the text to be drawn
    *
    * @return An image buffer with the text.
    */
-  Devel::PixelBuffer CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
+  Devel::PixelBuffer CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
 
   /**
    * @brief Combine the two RGBA image buffers together.
index 47c9bc0..f07e955 100644 (file)
@@ -323,7 +323,8 @@ struct Controller::Impl
     mMarkupProcessorEnabled( false ),
     mClipboardHideEnabled( true ),
     mIsAutoScrollEnabled( false ),
-    mAutoScrollDirectionRTL( false ),
+    mUpdateTextDirection( true ),
+    mIsTextDirectionRTL( false ),
     mUnderlineSetByString( false ),
     mShadowSetByString( false ),
     mOutlineSetByString( false ),
@@ -744,7 +745,8 @@ public:
   bool mMarkupProcessorEnabled:1;          ///< Whether the mark-up procesor is enabled.
   bool mClipboardHideEnabled:1;            ///< Whether the ClipboardHide function work or not
   bool mIsAutoScrollEnabled:1;             ///< Whether auto text scrolling is enabled.
-  CharacterDirection mAutoScrollDirectionRTL:1;  ///< Direction of auto scrolling, true if rtl
+  bool mUpdateTextDirection:1;             ///< Whether the text direction needs to be updated.
+  CharacterDirection mIsTextDirectionRTL:1;  ///< Whether the text direction is right to left or not
 
   bool mUnderlineSetByString:1;            ///< Set when underline is set by string (legacy) instead of map
   bool mShadowSetByString:1;               ///< Set when shadow is set by string (legacy) instead of map
index 6509467..c618006 100755 (executable)
@@ -222,7 +222,7 @@ bool Controller::IsAutoScrollEnabled() const
 
 CharacterDirection Controller::GetAutoScrollDirection() const
 {
-  return mImpl->mAutoScrollDirectionRTL;
+  return mImpl->mIsTextDirectionRTL;
 }
 
 float Controller::GetAutoScrollLineAlignment() const
@@ -554,6 +554,9 @@ void Controller::SetText( const std::string& text )
     // The natural size needs to be re-calculated.
     mImpl->mRecalculateNaturalSize = true;
 
+    // The text direction needs to be updated.
+    mImpl->mUpdateTextDirection = true;
+
     // Apply modifications to the model
     mImpl->mOperationsPending = ALL_OPERATIONS;
   }
@@ -2120,20 +2123,39 @@ void Controller::GetPlaceholderProperty( Property::Map& map )
 
 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
 {
-  if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
+  // Make sure the model is up-to-date before layouting
+  ProcessModifyEvents();
+
+  if ( mImpl->mUpdateTextDirection )
   {
-    return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
-  }
+    // Operations that can be done only once until the text changes.
+    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( GET_SCRIPTS       |
+                                                                           VALIDATE_FONTS    |
+                                                                           GET_LINE_BREAKS   |
+                                                                           GET_WORD_BREAKS   |
+                                                                           BIDI_INFO         |
+                                                                           SHAPE_TEXT        );
 
-  const Character character = mImpl->mModel->mLogicalModel->mText[0];
-  Script script = TextAbstraction::GetCharacterScript( character );
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
 
-  if( TextAbstraction::IsRightToLeftScript( script ) )
-  {
-    return Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT;
+    // Make sure the model is up-to-date before layouting
+    mImpl->UpdateModel( onlyOnceOperations );
+
+    Vector3 naturalSize;
+    DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
+                static_cast<OperationsMask>( onlyOnceOperations |
+                                             LAYOUT | REORDER | UPDATE_DIRECTION ),
+                naturalSize.GetVectorXY() );
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+
+    mImpl->mUpdateTextDirection = false;
   }
 
-  return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
+  return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
 }
 
 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
@@ -2178,6 +2200,13 @@ Controller::UpdateTextType Controller::Relayout( const Size& size )
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
 
+    if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
+        ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
+        ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
+    {
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+    }
+
     // Layout operations that need to be done if the size changes.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
                                                              LAYOUT                    |
@@ -3415,7 +3444,8 @@ bool Controller::DoRelayout( const Size& size,
     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
 
     // Set the layout parameters.
-    Layout::Parameters layoutParameters( size,
+    const Vector2 sizeOffset = Vector2(outlineWidth * 2.0f, outlineWidth * 2.0f); // The outline should be fit into the bounding box
+    Layout::Parameters layoutParameters( size - sizeOffset,
                                          textBuffer,
                                          lineBreakInfo.Begin(),
                                          wordBreakInfo.Begin(),
@@ -3482,7 +3512,7 @@ bool Controller::DoRelayout( const Size& size,
 
       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
       {
-        mImpl->mAutoScrollDirectionRTL = false;
+        mImpl->mIsTextDirectionRTL = false;
       }
 
       // Reorder the lines
@@ -3520,7 +3550,7 @@ bool Controller::DoRelayout( const Size& size,
             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
             if ( firstline )
             {
-              mImpl->mAutoScrollDirectionRTL = firstline->direction;
+              mImpl->mIsTextDirectionRTL = firstline->direction;
             }
           }
         }
@@ -3553,7 +3583,7 @@ bool Controller::DoRelayout( const Size& size,
 #if defined(DEBUG_ENABLED)
   std::string currentText;
   GetText( currentText );
-  DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false",  currentText.c_str() );
 #endif
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
   return viewUpdated;
@@ -3648,6 +3678,9 @@ void Controller::TextReplacedEvent()
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
   // Apply modifications to the model
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
@@ -3666,6 +3699,9 @@ void Controller::TextInsertedEvent()
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
   // Apply modifications to the model; TODO - Optimize this
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
@@ -3684,6 +3720,9 @@ void Controller::TextDeletedEvent()
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
   // Apply modifications to the model; TODO - Optimize this
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
@@ -3785,6 +3824,9 @@ void Controller::ResetText()
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
   // Apply modifications to the model
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
@@ -3851,6 +3893,9 @@ void Controller::ShowPlaceholderText()
     // The natural size needs to be re-calculated.
     mImpl->mRecalculateNaturalSize = true;
 
+    // The text direction needs to be updated.
+    mImpl->mUpdateTextDirection = true;
+
     // Apply modifications to the model
     mImpl->mOperationsPending = ALL_OPERATIONS;
 
index f8089a2..fab9327 100644 (file)
@@ -66,15 +66,12 @@ const char* VERTEX_SHADER_SCROLL = DALI_COMPOSE_SHADER(
     mediump vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy );\n
     mediump vec2 visualSize = mix( uSize.xy * size, size, offsetSizeMode.zw );\n
     \n
-    mediump float delta = floor ( uDelta ) + 0.5;\n
-    vTexCoord.x = ( delta + uHorizontalAlign * ( uTextureSize.x - visualSize.x - uGap ) + floor( aPosition.x * visualSize.x ) + 0.5 - uGap * 0.5 ) / uTextureSize.x + 0.5;\n
+    vTexCoord.x = ( uDelta + uHorizontalAlign * ( uTextureSize.x - visualSize.x - uGap ) + floor( aPosition.x * visualSize.x ) + 0.5 - uGap * 0.5 ) / uTextureSize.x + 0.5;\n
     vTexCoord.y = ( uVerticalAlign * ( uTextureSize.y - visualSize.y ) + floor( aPosition.y * visualSize.y ) + 0.5 ) / ( uTextureSize.y ) + 0.5;\n
     \n
     mediump vec4 vertexPosition = vec4( floor( ( aPosition + anchorPoint ) * visualSize + ( visualOffset + origin ) * uSize.xy ), 0.0, 1.0 );\n
-    mediump vec4 nonAlignedVertex = uViewMatrix * uModelMatrix * vertexPosition;\n
-    mediump vec4 pixelAlignedVertex = vec4 ( floor( nonAlignedVertex.xyz ), 1.0 );\n
     \n
-    gl_Position = uProjection * pixelAlignedVertex;\n
+    gl_Position = uProjection * uViewMatrix * uModelMatrix * vertexPosition;\n
   }\n
 );
 
@@ -298,8 +295,20 @@ void TextScroller::SetParameters( Actor scrollingTextActor, Renderer renderer, T
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters wrapGap[%f]\n", wrapGap );
 
-  const float horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[ horizontalAlignment ][ direction ];
+  float horizontalAlign;
+
+  if( textureSize.x > controlSize.x )
+  {
+    // if Text is elided, scroll should start at the begin of text.
+    horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[HorizontalAlignment::BEGIN][ direction ];
+  }
+  else
+  {
+    horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[ horizontalAlignment ][ direction ];
+  }
+
   const float verticalAlign = VERTICAL_ALIGNMENT_TABLE[ verticalAlignment ];
+
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters horizontalAlign[%f], verticalAlign[%f]\n", horizontalAlign, verticalAlign );
 
   scrollingTextActor.RegisterProperty( "uTextureSize", textureSize );
index 5373a6a..e359dc7 100755 (executable)
@@ -264,18 +264,21 @@ void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
 
 LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
 {
-  // 1) Check first in the cached line.
+  // 1) Check line is empty or not.
+  if( mLines.Empty() )
+  {
+    return 0u;
+  }
 
+  // 2) Check in the cached line.
   const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
-
   if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
       ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
   {
     return mCachedLineIndex;
   }
 
-  // 2) Is not in the cached line. Check in the other lines.
-
+  // 3) Is not in the cached line. Check in the other lines.
   LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
 
   for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
old mode 100644 (file)
new mode 100755 (executable)
index 9ac0b90..84ae1c9
@@ -19,9 +19,9 @@
 #include "animated-image-visual.h"
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/gif-loading.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/integration-api/debug.h>
+#include <memory>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
 #include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
+#include <dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h>
 #include <dali-toolkit/internal/visuals/image/image-visual.h>
 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
 
 namespace Dali
 {
@@ -65,12 +67,17 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 /**
  * Multi-image  Flow of execution
  *
- *   | DoSetProperties()
+ *   | New
+ *   |   DoSetProperties()
  *   |   LoadFirstBatch()
- *   |     cache->LoadBatch()
+ *   |     new cache
+ *   |       cache->LoadBatch()
  *   |
  *   | DoSetOnStage()
+ *   |   PrepareTextureSet()
+ *   |     cache->FirstFrame()
  *   |   CreateRenderer()    (Doesn't become ready until first frame loads)
+ *   |   StartFirstFrame()
  *   |
  *   | FrameReady(textureSet)
  *   |   start first frame:
@@ -94,16 +101,21 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 
 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties )
 {
-  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
-  visual->mImageUrl = imageUrl;
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
+  visual->InitializeGif( imageUrl );
   visual->SetProperties( properties );
 
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
   return visual;
 }
 
 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const Property::Array& imageUrls, const Property::Map& properties )
 {
-  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
   visual->mImageUrls = new ImageCache::UrlList();
   visual->mImageUrls->reserve( imageUrls.Count() );
 
@@ -114,26 +126,45 @@ AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCach
     urlStore.mUrl = imageUrls[i].Get<std::string>();
     visual->mImageUrls->push_back( urlStore );
   }
-
+  visual->mFrameCount = imageUrls.Count();
   visual->SetProperties( properties );
-  // starts loading immediately
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
   return visual;
 }
 
 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl )
 {
-  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
-  visual->mImageUrl = imageUrl;
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
+  visual->InitializeGif( imageUrl );
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
 
   return visual;
 }
 
+void AnimatedImageVisual::InitializeGif( const VisualUrl& imageUrl )
+{
+  mImageUrl = imageUrl;
+  mGifLoading = GifLoading::New( imageUrl.GetUrl() );
+  mFrameCount = mGifLoading->GetImageCount();
+  mGifLoading->LoadFrameDelays( mFrameDelayContainer );
+}
+
 AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
   mFrameDelayTimer(),
   mPlacementActor(),
   mPixelArea( FULL_TEXTURE_RECT ),
   mImageUrl(),
+  mGifLoading( nullptr ),
   mCurrentFrameIndex( 0 ),
   mImageUrls( NULL ),
   mImageCache( NULL ),
@@ -141,6 +172,7 @@ AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
   mBatchSize( 1 ),
   mFrameDelay( 100 ),
   mUrlIndex( 0 ),
+  mFrameCount( 0 ),
   mImageSize(),
   mWrapModeU( WrapMode::DEFAULT ),
   mWrapModeV( WrapMode::DEFAULT ),
@@ -159,7 +191,7 @@ void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize )
   {
     if( mImageUrl.IsValid() )
     {
-      mImageSize = Dali::GetGifImageSize( mImageUrl.GetUrl() );
+      mImageSize = mGifLoading->GetImageSize();
     }
     else if( mImageUrls && mImageUrls->size() > 0 )
     {
@@ -245,11 +277,6 @@ void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
       }
     }
   }
-
-  if( mImageUrls && mImageUrls->size() > 0 )
-  {
-    LoadFirstBatch();
-  }
 }
 
 void AnimatedImageVisual::DoSetProperty( Property::Index index,
@@ -347,9 +374,6 @@ void AnimatedImageVisual::DoSetOffStage( Actor& actor )
     mFrameDelayTimer.Reset();
   }
 
-  mTextureRectContainer.Clear();
-  mFrameDelayContainer.Clear();
-
   actor.RemoveRenderer( mImpl->mRenderer );
   mImpl->mRenderer.Reset();
   mPlacementActor.Reset();
@@ -366,7 +390,7 @@ void AnimatedImageVisual::OnSetTransform()
 void AnimatedImageVisual::CreateRenderer()
 {
   bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
-  bool atlasing = (mTextureRectContainer.Count() > 0) ;
+  bool atlasing = false;
   Shader shader = ImageVisual::GetImageShader( mFactoryCache, atlasing, defaultWrapMode );
 
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
@@ -389,27 +413,38 @@ void AnimatedImageVisual::CreateRenderer()
   }
 
   mCurrentFrameIndex = 0;
-
-  if( mTextureRectContainer.Count() > 0 )
-  {
-    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
-  }
 }
 
 void AnimatedImageVisual::LoadFirstBatch()
 {
-  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch()\n");
-
   // Ensure the batch size and cache size are no bigger than the number of URLs,
   // and that the cache is at least as big as the batch size.
-  uint16_t numUrls = mImageUrls->size();
-  uint16_t batchSize = std::min( mBatchSize, numUrls );
-  uint16_t cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+  uint16_t numUrls = 0;
+  uint16_t batchSize = 1;
+  uint16_t cacheSize = 1;
+
+  if( mImageUrls )
+  {
+    numUrls = mImageUrls->size();
+  }
+  else
+  {
+    numUrls = mFrameCount;
+  }
+
+  batchSize = std::min( mBatchSize, numUrls );
+  cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch()  batchSize:%d  cacheSize:%d\n", batchSize, cacheSize);
 
   mUrlIndex = 0;
   TextureManager& textureManager = mFactoryCache.GetTextureManager();
 
-  if( batchSize > 0 && cacheSize > 0 )
+  if( mGifLoading != nullptr )
+  {
+    mImageCache = new RollingGifImageCache( textureManager, *mGifLoading, mFrameCount, *this, cacheSize, batchSize );
+  }
+  else if( batchSize > 0 && cacheSize > 0 )
   {
     if( cacheSize < numUrls )
     {
@@ -424,6 +459,10 @@ void AnimatedImageVisual::LoadFirstBatch()
   {
     mImageCache = new RollingImageCache( textureManager, *mImageUrls, *this, 1, 1 );
   }
+  if (!mImageCache)
+  {
+    DALI_LOG_ERROR("mImageCache is null");
+  }
 }
 
 void AnimatedImageVisual::StartFirstFrame( TextureSet& textureSet )
@@ -439,55 +478,37 @@ void AnimatedImageVisual::StartFirstFrame( TextureSet& textureSet )
     mPlacementActor.Reset();
   }
 
-  int frameDelay = mFrameDelay;
-  if( mFrameDelayContainer.Count() > 1 )
+  mCurrentFrameIndex = 0;
+
+  if( mFrameCount > 1 )
   {
-    frameDelay = mFrameDelayContainer[0];
-  }
-  mFrameDelayTimer = Timer::New( frameDelay );
-  mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
-  mFrameDelayTimer.Start();
+    int frameDelay = mFrameDelay; // from URL array
+    if( mFrameDelayContainer.Count() > 0 ) // from GIF
+    {
+      frameDelay = mFrameDelayContainer[0];
+    }
 
-  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady()\n");
+    mFrameDelayTimer = Timer::New( frameDelay );
+    mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
+    mFrameDelayTimer.Start();
+  }
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::READY)\n");
   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
 }
 
 TextureSet AnimatedImageVisual::PrepareTextureSet()
 {
   TextureSet textureSet;
-  if( mImageUrl.IsValid() )
+  if (mImageCache)
+    textureSet = mImageCache->FirstFrame();
+  if( textureSet )
   {
-    textureSet = PrepareAnimatedGifImage();
+    SetImageSize( textureSet );
   }
   else
   {
-    textureSet = mImageCache->FirstFrame();
-    if( textureSet )
-    {
-      SetImageSize( textureSet );
-    }
-  }
-  return textureSet;
-}
-
-TextureSet AnimatedImageVisual::PrepareAnimatedGifImage()
-{
-  TextureSet textureSet;
-
-  // load from image file
-  std::vector<Dali::PixelData> pixelDataList;
-
-  if( mImageUrl.IsLocalResource() )
-  {
-    if( Dali::LoadAnimatedGifFromFile( mImageUrl.GetUrl().c_str() , pixelDataList, mFrameDelayContainer ) )
-    {
-      mImageSize.SetWidth( pixelDataList[0].GetWidth() );
-      mImageSize.SetHeight( pixelDataList[0].GetHeight() );
-
-      Texture texture = Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer );
-      textureSet = TextureSet::New();
-      textureSet.SetTexture( 0, texture );
-    }
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::FAILED)\n");
+    ResourceReady( Toolkit::Visual::ResourceStatus::FAILED );
   }
 
   return textureSet;
@@ -522,29 +543,31 @@ void AnimatedImageVisual::FrameReady( TextureSet textureSet )
 
 bool AnimatedImageVisual::DisplayNextFrame()
 {
-  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame() start\n");
-
-  if( mFrameDelayContainer.Count() > 0 )
+  if( mFrameCount > 1 )
   {
     // Wrap the frame index
     ++mCurrentFrameIndex;
-    mCurrentFrameIndex %= mFrameDelayContainer.Count();
+    mCurrentFrameIndex %= mFrameCount;
+  }
+  DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) FrameCount:%d\n", this, mCurrentFrameIndex);
 
-    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
+  if( mFrameDelayContainer.Count() > 0 )
+  {
+    unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex];
 
-    if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] )
+    if( mFrameDelayTimer.GetInterval() != delay )
     {
-      mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] );
+      mFrameDelayTimer.SetInterval( delay );
     }
   }
-  else if( mImageCache )
+
+  TextureSet textureSet;
+  if (mImageCache)
+    textureSet = mImageCache->NextFrame();
+  if( textureSet )
   {
-    TextureSet textureSet = mImageCache->NextFrame();
-    if( textureSet )
-    {
-      SetImageSize( textureSet );
-      mImpl->mRenderer.SetTextures( textureSet );
-    }
+    SetImageSize( textureSet );
+    mImpl->mRenderer.SetTextures( textureSet );
   }
 
   // Keep timer ticking
index 1e71ba1..5c9b31c 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/math/vector4.h>
 #include <dali/public-api/object/weak-handle.h>
 #include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
@@ -184,6 +185,7 @@ private:
   /**
    * Adds the texture set to the renderer, and the renderer to the
    * placement actor, and starts the frame timer
+   * @param[in] textureSet The texture set to apply
    */
   void StartFirstFrame( TextureSet& textureSet );
 
@@ -193,18 +195,14 @@ private:
   TextureSet PrepareTextureSet();
 
   /**
-   * Load the gif image and pack the frames into atlas.
-   * @return The atlas texture.
-   */
-  TextureSet PrepareAnimatedGifImage();
-
-  /**
    * Set the image size from the texture set
+   * @param[in] textureSet The texture set to get the size from
    */
   void SetImageSize( TextureSet& textureSet );
 
   /**
    * Called when the next frame is ready.
+   * @param[in] textureSet the texture set to apply
    */
   void FrameReady( TextureSet textureSet );
 
@@ -214,6 +212,11 @@ private:
    */
   bool DisplayNextFrame();
 
+  /**
+   * Initialize the gif variables.
+   * @param[in] imageUrl The url of the animated gif
+   */
+  void InitializeGif( const VisualUrl& imageUrl );
 
   // Undefined
   AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual );
@@ -227,10 +230,10 @@ private:
   WeakHandle<Actor> mPlacementActor;
 
   // Variables for GIF player
-  Dali::Vector<Vector4> mTextureRectContainer;
   Dali::Vector<uint32_t> mFrameDelayContainer;
   Vector4 mPixelArea;
   VisualUrl mImageUrl;
+  std::unique_ptr<Dali::GifLoading> mGifLoading; // Only needed for animated gifs
   uint32_t mCurrentFrameIndex; // Frame index into textureRects
 
   // Variables for Multi-Image player
@@ -242,6 +245,7 @@ private:
   uint16_t mUrlIndex;
 
   // Shared variables
+  uint32_t mFrameCount; // Number of frames
   ImageDimensions mImageSize;
 
   Dali::WrapMode::Type mWrapModeU:3;
index 03dbcbc..b1713d2 100644 (file)
@@ -17,6 +17,9 @@
 // CLASS HEADER
 #include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
 
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+
 namespace Dali
 {
 namespace Toolkit
@@ -32,7 +35,8 @@ const bool ENABLE_ORIENTATION_CORRECTION( true );
 FixedImageCache::FixedImageCache(
   TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
   unsigned int batchSize )
-: ImageCache( textureManager, urlList, observer, batchSize ),
+: ImageCache( textureManager, observer, batchSize ),
+  mImageUrls( urlList ),
   mFront(0u)
 {
   mReadyFlags.reserve( mImageUrls.size() );
@@ -102,10 +106,28 @@ void FixedImageCache::LoadBatch()
     // need to account for this inside the UploadComplete method using mRequestingLoad.
     mRequestingLoad = true;
 
-    mImageUrls[ mUrlIndex ].mTextureId =
-      mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
-                                   SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
-                                   this, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED  );
+    bool synchronousLoading = false;
+    bool atlasingStatus = false;
+    bool loadingStatus = false;
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    AtlasUploadObserver* atlasObserver = nullptr;
+    ImageAtlasManagerPtr imageAtlasManager = nullptr;
+    Vector4 textureRect;
+    auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+    mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR, maskInfo,
+      synchronousLoading, mImageUrls[ mUrlIndex ].mTextureId, textureRect,
+      atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+      Dali::WrapMode::Type::DEFAULT, this,
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+      preMultiply );
+
+    if( loadingStatus == false )  // not loading, means it's already ready.
+    {
+      SetImageFrameReady( mImageUrls[ mUrlIndex ].mTextureId );
+    }
     mRequestingLoad = false;
     ++mUrlIndex;
   }
@@ -144,7 +166,8 @@ void FixedImageCache::UploadComplete(
   int32_t        textureId,
   TextureSet     textureSet,
   bool           useAtlasing,
-  const Vector4& atlasRect )
+  const Vector4& atlasRect,
+  bool           preMultiplied)
 {
   bool frontFrameReady = IsFrontReady();
 
index 4c59447..570b2d7 100644 (file)
@@ -28,7 +28,7 @@ namespace Toolkit
 namespace Internal
 {
 
-class FixedImageCache : public ImageCache
+class FixedImageCache : public ImageCache, public TextureUploadObserver
 {
 public:
   /**
@@ -95,9 +95,11 @@ protected:
     int32_t        textureId,
     TextureSet     textureSet,
     bool           useAtlasing,
-    const Vector4& atlasRect );
+    const Vector4& atlasRect,
+    bool           premultiplied) override;
 
-protected:
+private:
+  std::vector<UrlStore>& mImageUrls;
   std::vector<bool> mReadyFlags;
   unsigned int      mFront;
 };
index 1d0db6f..84e5f66 100644 (file)
@@ -24,12 +24,10 @@ namespace Internal
 {
 
 ImageCache::ImageCache( TextureManager&                 textureManager,
-                        UrlList&                        urlList,
                         ImageCache::FrameReadyObserver& observer,
                         unsigned int                    batchSize )
 : mTextureManager( textureManager ),
   mObserver( observer ),
-  mImageUrls( urlList ),
   mBatchSize( batchSize ),
   mUrlIndex(0u),
   mWaitingForReadyFrame(false),
index 12e89e9..1a7ae75 100644 (file)
@@ -28,7 +28,7 @@ namespace Toolkit
 namespace Internal
 {
 
-class ImageCache : public TextureUploadObserver
+class ImageCache
 {
 public:
   /**
@@ -67,7 +67,6 @@ public:
    * batch and cache sizes. The cache is as large as the number of urls.
    */
   ImageCache( TextureManager&                 textureManager,
-              UrlList&                        urlList,
               ImageCache::FrameReadyObserver& observer,
               unsigned int                    batchSize );
 
@@ -89,7 +88,6 @@ public:
 protected:
   TextureManager&        mTextureManager;
   FrameReadyObserver&    mObserver;
-  std::vector<UrlStore>& mImageUrls;
   unsigned int           mBatchSize;
   unsigned int           mUrlIndex;
   bool                   mWaitingForReadyFrame:1;
diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp
new file mode 100644 (file)
index 0000000..ed61adb
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017 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 "rolling-gif-image-cache.h"
+
+// EXTERNAL HEADERS
+
+// INTERNAL HEADERS
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
+
+#define LOG_CACHE                                                       \
+  {                                                                     \
+    std::ostringstream oss;                                             \
+    oss<<"Size:"<<mQueue.Count()<<" [ ";                                \
+    for(std::size_t _i=0; _i<mQueue.Count(); ++_i)                      \
+    {                                                                   \
+      oss<<_i<<                                                         \
+        "={ frm#: " << mQueue[_i].mFrameNumber <<                        \
+           " tex: " << mImageUrls[mQueue[_i].mFrameNumber].mTextureId<<"}, ";  \
+    }                                                                   \
+    oss<<" ]"<<std::endl;                                               \
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"%s",oss.str().c_str()); \
+  }
+
+#else
+  #define LOG_CACHE
+#endif
+
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+RollingGifImageCache::RollingGifImageCache(
+  TextureManager& textureManager, GifLoading& gifLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer,
+  uint16_t cacheSize, uint16_t batchSize )
+: ImageCache( textureManager, observer, batchSize ),
+  mGifLoading( gifLoading ),
+  mFrameCount( frameCount ),
+  mFrameIndex( 0 ),
+  mCacheSize( cacheSize ),
+  mQueue( cacheSize )
+{
+  mImageUrls.resize( mFrameCount );
+  LoadBatch();
+}
+
+RollingGifImageCache::~RollingGifImageCache()
+{
+  while( !mQueue.IsEmpty() )
+  {
+    ImageFrame imageFrame = mQueue.PopFront();
+    Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+  }
+}
+
+TextureSet RollingGifImageCache::FirstFrame()
+{
+  return GetFrontTextureSet();
+}
+
+TextureSet RollingGifImageCache::NextFrame()
+{
+  TextureSet textureSet;
+
+  ImageFrame imageFrame = mQueue.PopFront();
+  Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+  mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+
+  LoadBatch();
+
+  return GetFrontTextureSet();
+}
+
+bool RollingGifImageCache::IsFrontReady() const
+{
+  return ( !mQueue.IsEmpty() );
+}
+
+void RollingGifImageCache::LoadBatch()
+{
+  // Try and load up to mBatchSize images, until the cache is filled.
+  // Once the cache is filled, as frames progress, the old frame is
+  // removed, and another frame is loaded
+
+  std::vector<Dali::PixelData> pixelDataList;
+
+  // Get the smallest number of frames we need to load
+  int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() );
+  DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::LoadBatch() mFrameIndex:%d  batchSize:%d\n", mFrameIndex, batchSize );
+
+  if( mGifLoading.LoadNextNFrames(  mFrameIndex, batchSize, pixelDataList) )
+  {
+    unsigned int pixelDataListCount = pixelDataList.size();
+
+    for( unsigned int i = 0; i < pixelDataListCount && !mQueue.IsFull(); ++i )
+    {
+      ImageFrame imageFrame;
+
+      // create the texture for uploading the pixel data
+      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                      pixelDataList[i].GetPixelFormat(),
+                                      pixelDataList[i].GetWidth(),
+                                      pixelDataList[i].GetHeight() );
+
+      texture.Upload( pixelDataList[i] );
+
+      mImageUrls[ mUrlIndex ].mUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
+      imageFrame.mFrameNumber = mUrlIndex;
+
+      ++mUrlIndex;
+      mUrlIndex %= mImageUrls.size();
+
+      mQueue.PushBack( imageFrame );
+
+      bool synchronousLoading = false;
+      bool atlasingStatus = false;
+      bool loadingStatus = false;
+      TextureManager::MaskingDataPointer maskInfo = nullptr;
+      AtlasUploadObserver* atlasObserver = nullptr;
+      ImageAtlasManagerPtr imageAtlasManager = nullptr;
+      Vector4 textureRect;
+      auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+      mTextureManager.LoadTexture(
+        mImageUrls[ imageFrame.mFrameNumber ].mUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+        SamplingMode::BOX_THEN_LINEAR, maskInfo,
+        synchronousLoading, mImageUrls[ imageFrame.mFrameNumber ].mTextureId, textureRect,
+        atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+        Dali::WrapMode::Type::DEFAULT, NULL,
+        atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply );
+    }
+
+    mFrameIndex += batchSize;
+    mFrameIndex %= mFrameCount;
+  }
+
+  LOG_CACHE;
+}
+
+TextureSet RollingGifImageCache::GetFrontTextureSet() const
+{
+  DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[ 0 ].mFrameNumber );
+
+  TextureManager::TextureId textureId = GetCachedTextureId( 0 );
+  return mTextureManager.GetTextureSet( textureId );
+}
+
+TextureManager::TextureId RollingGifImageCache::GetCachedTextureId( int index ) const
+{
+  return mImageUrls[ mQueue[ index ].mFrameNumber ].mTextureId;
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h
new file mode 100644 (file)
index 0000000..d912ab3
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2018 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/gif-loading.h>
+#include <dali/devel-api/common/circular-queue.h>
+#include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Class to manage a rolling cache of GIF images, where the cache size
+ * is smaller than the total number of images.
+ *
+ * Frames are always ready, so the observer.FrameReady callback is never triggered;
+ * the FirstFrame and NextFrame APIs will always return a texture.
+ */
+class RollingGifImageCache : public ImageCache
+{
+public:
+  /**
+   * Constructor.
+   * @param[in] textureManager The texture manager
+   * @param[in] gifLoader The loaded gif image
+   * @param[in] frameCount The number of frames in the gif
+   * @param[in] observer FrameReady observer
+   * @param[in] cacheSize The size of the cache
+   * @param[in] batchSize The size of a batch to load
+   *
+   * This will start loading textures immediately, according to the
+   * batch and cache sizes.
+   */
+  RollingGifImageCache( TextureManager&                 textureManager,
+                        GifLoading&                     gifLoader,
+                        uint32_t                        frameCount,
+                        ImageCache::FrameReadyObserver& observer,
+                        uint16_t                        cacheSize,
+                        uint16_t                        batchSize );
+
+  /**
+   * Destructor
+   */
+  virtual ~RollingGifImageCache();
+
+  /**
+   * Get the first frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  virtual TextureSet FirstFrame();
+
+  /**
+   * Get the next frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   * This will trigger the loading of the next batch.
+   */
+  virtual TextureSet NextFrame();
+
+private:
+  /**
+   * @return true if the front frame is ready
+   */
+  bool IsFrontReady() const;
+
+  /**
+   * Load the next batch of images
+   */
+  void LoadBatch();
+
+  /**
+   * Get the texture set of the front frame.
+   * @return the texture set
+   */
+  TextureSet GetFrontTextureSet() const;
+
+  /**
+   * Get the texture id of the given index
+   */
+  TextureManager::TextureId GetCachedTextureId( int index ) const;
+
+private:
+  /**
+   * Secondary class to hold readiness and index into url
+   */
+  struct ImageFrame
+  {
+    unsigned int mFrameNumber = 0u;
+  };
+
+  GifLoading&               mGifLoading;
+  uint32_t                  mFrameCount;
+  int                       mFrameIndex;
+  std::vector<UrlStore>     mImageUrls;
+  uint16_t                  mCacheSize;
+  CircularQueue<ImageFrame> mQueue;
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif
index 9c3f82f..37c7a7d 100644 (file)
@@ -18,6 +18,7 @@
 #include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
 
 // INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
 #include <dali/integration-api/debug.h>
 
 // EXTERNAL HEADERS
@@ -60,7 +61,8 @@ namespace Internal
 RollingImageCache::RollingImageCache(
   TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
   uint16_t cacheSize, uint16_t batchSize )
-: ImageCache( textureManager, urlList, observer, batchSize ),
+: ImageCache( textureManager, observer, batchSize ),
+  mImageUrls( urlList ),
   mQueue( cacheSize )
 {
   LoadBatch();
@@ -139,10 +141,24 @@ void RollingImageCache::LoadBatch()
     // need to account for this inside the UploadComplete method using mRequestingLoad.
     mRequestingLoad = true;
 
-    mImageUrls[ imageFrame.mUrlIndex ].mTextureId =
-      mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
-                                   SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
-                                   this, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+    bool synchronousLoading = false;
+    bool atlasingStatus = false;
+    bool loadingStatus = false;
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    AtlasUploadObserver* atlasObserver = nullptr;
+    ImageAtlasManagerPtr imageAtlasManager = nullptr;
+    Vector4 textureRect;
+    auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+    mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR, maskInfo,
+      synchronousLoading, mImageUrls[ imageFrame.mUrlIndex ].mTextureId, textureRect,
+      atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+      Dali::WrapMode::Type::DEFAULT, this,
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+      preMultiply );
+
     mRequestingLoad = false;
   }
 
@@ -186,7 +202,8 @@ void RollingImageCache::UploadComplete(
   int32_t        textureId,
   TextureSet     textureSet,
   bool           useAtlasing,
-  const Vector4& atlasRect )
+  const Vector4& atlasRect,
+  bool           preMultiplied )
 {
   DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
   LOG_CACHE;
index 1aed961..76a79ec 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_ROLLING_IMAGE_CACHE_H
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
@@ -34,7 +34,7 @@ namespace Internal
  * Class to manage a rolling cache of images, where the cache size
  * is smaller than the total number of images.
  */
-class RollingImageCache : public ImageCache
+class RollingImageCache : public ImageCache, public TextureUploadObserver
 {
 public:
   /**
@@ -111,7 +111,8 @@ protected:
     int32_t        textureId,
     TextureSet     textureSet,
     bool           useAtlasing,
-    const Vector4& atlasRect );
+    const Vector4& atlasRect,
+    bool           preMultiplied ) override;
 
 private:
   /**
@@ -119,10 +120,11 @@ private:
    */
   struct ImageFrame
   {
-    unsigned int mUrlIndex;
-    bool mReady;
+    unsigned int mUrlIndex = 0u;
+    bool mReady = false;
   };
 
+  std::vector<UrlStore>& mImageUrls;
   CircularQueue<ImageFrame> mQueue;
 };
 
index 2d8008f..2058e1b 100644 (file)
@@ -25,6 +25,7 @@
 //INTERNAL INCLUDES
 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
 #include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
@@ -88,7 +89,8 @@ ColorVisualPtr ColorVisual::New( VisualFactoryCache& factoryCache, const Propert
 }
 
 ColorVisual::ColorVisual( VisualFactoryCache& factoryCache )
-: Visual::Base( factoryCache )
+: Visual::Base( factoryCache ),
+  mRenderIfTransparent( false )
 {
 }
 
@@ -122,13 +124,27 @@ void ColorVisual::DoSetProperties( const Property::Map& propertyMap )
       DALI_LOG_ERROR("ColorVisual: mixColor property has incorrect type\n");
     }
   }
+
+  Property::Value* renderIfTransparentValue = propertyMap.Find( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, RENDER_IF_TRANSPARENT_NAME );
+  if( renderIfTransparentValue )
+  {
+    if( ! renderIfTransparentValue->Get( mRenderIfTransparent ) )
+    {
+      DALI_LOG_ERROR( "ColorVisual: renderIfTransparent property has incorrect type: %d\n", renderIfTransparentValue->GetType() );
+    }
+  }
 }
 
 void ColorVisual::DoSetOnStage( Actor& actor )
 {
   InitializeRenderer();
 
-  actor.AddRenderer( mImpl->mRenderer );
+  // Only add the renderer if it's not fully transparent
+  // We cannot avoid creating a renderer as it's used in the base class
+  if( mRenderIfTransparent || mImpl->mMixColor.a > 0.0f )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+  }
 
   // Color Visual generated and ready to display
   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
@@ -139,6 +155,7 @@ void ColorVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Clear();
   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR );
   map.Insert( Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor );
+  map.Insert( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, mRenderIfTransparent );
 }
 
 void ColorVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
index 939d40e..4b6dca6 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_COLOR_VISUAL_H
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -112,6 +112,10 @@ private:
 
   // Undefined
   ColorVisual& operator=( const ColorVisual& colorRenderer );
+
+private:
+
+  bool mRenderIfTransparent; ///< Whether we should render even if the mix-color is transparent.
 };
 
 } // namespace Internal
index 51924f0..d9ea9cd 100644 (file)
@@ -698,6 +698,11 @@ void ImageVisual::CreateRenderer( TextureSet& textureSet )
 
   //Register transform properties
   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+  if( IsPreMultipliedAlphaEnabled() )
+  {
+    EnablePreMultipliedAlpha( true );
+  }
 }
 
 void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage )
@@ -754,7 +759,6 @@ void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage )
   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
 }
 
-
 bool ImageVisual::IsSynchronousResourceLoading() const
 {
   return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
@@ -775,12 +779,20 @@ void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& t
     atlasUploadObserver = this;
   }
 
+  auto preMultiplyOnLoad = mFactoryCache.GetPreMultiplyOnLoad()
+    ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+    : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
   textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
                                          mMaskingData, IsSynchronousResourceLoading(), mTextureId,
                                          atlasRect, atlasing, mLoading, mWrapModeU,
                                          mWrapModeV, textureObserver, atlasUploadObserver, atlasManager,
-                                         mOrientationCorrection,
-                                         forceReload );
+                                         mOrientationCorrection, forceReload, preMultiplyOnLoad);
+
+  if( textures && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
+  {
+    EnablePreMultipliedAlpha( true );
+  }
 
   if( atlasing ) // Flag needs to be set before creating renderer
   {
@@ -1073,7 +1085,7 @@ void ImageVisual::UploadCompleted()
 
 // From Texture Manager
 void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas,
-                                  const Vector4& atlasRectangle )
+                                  const Vector4& atlasRectangle, bool preMultiplied )
 {
   Toolkit::Visual::ResourceStatus resourceStatus;
   Actor actor = mPlacementActor.GetHandle();
@@ -1085,6 +1097,10 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
       {
         mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
       }
+      else if( preMultiplied )
+      {
+        EnablePreMultipliedAlpha( true );
+      }
 
       actor.AddRenderer( mImpl->mRenderer );
       // reset the weak handle so that the renderer only get added to actor once
index d78ceca..1a9230c 100644 (file)
@@ -256,7 +256,7 @@ public:
    * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
    * This callback is the place to add the renderer as it would be called once the loading is finished.
    */
-  virtual void UploadCompleted();
+  virtual void UploadCompleted() override;
 
   /**
    * @copydoc TextureUploadObserver::UploadCompleted
@@ -264,7 +264,8 @@ public:
    * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
    * This callback is the place to add the renderer as it would be called once the loading is finished.
    */
-  virtual void UploadComplete( bool success, int32_t textureId, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle );
+  virtual void UploadComplete( bool success, int32_t textureId, TextureSet textureSet,
+                               bool usingAtlas, const Vector4& atlasRectangle, bool preMultiplied ) override;
 
 private:
 
index e44b005..e4c62f8 100755 (executable)
@@ -35,6 +35,7 @@
 #include <dali-toolkit/internal/text/text-effects-style.h>
 #include <dali-toolkit/internal/text/script-run.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 
 namespace Dali
 {
@@ -697,7 +698,7 @@ void TextVisual::UpdateRenderer()
 
       const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled );
 
-      TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsEmoji, styleEnabled );
+      TextureSet textureSet = GetTextTexture( mImpl->mTransform.mSize, hasMultipleTextColors, containsEmoji, styleEnabled );
       mImpl->mRenderer.SetTextures( textureSet );
 
       Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsEmoji, styleEnabled );
@@ -752,8 +753,11 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
   // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
   Pixel::Format textPixelFormat = ( containsEmoji || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8;
 
+  // Check the text direction
+  Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
+
   // Create a texture for the text without any styles
-  PixelData data = mTypesetter->Render( size, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
+  PixelData data = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
 
   // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
   // In that case, create a texture. TODO: should tile the text.
@@ -771,7 +775,7 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
   if ( styleEnabled )
   {
     // Create RGBA texture for all the text styles (without the text itself)
-    PixelData styleData = mTypesetter->Render( size, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
+    PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
 
     Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
                                          styleData.GetPixelFormat(),
@@ -787,7 +791,7 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
   if ( containsEmoji && !hasMultipleTextColors )
   {
     // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
-    PixelData maskData = mTypesetter->Render( size, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
+    PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
 
     Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
                                         maskData.GetPixelFormat(),
index 11d3b0f..7f62d22 100644 (file)
@@ -87,6 +87,22 @@ const char * const  BROKEN_IMAGE_URL( DALI_IMAGE_DIR "broken.png" ); ///< URL Fo
 const int           INVALID_INDEX( -1 );                             ///< Invalid index used to represent a non-existant TextureInfo struct
 const int           INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index
 
+
+void PreMultiply( Devel::PixelBuffer pixelBuffer, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+  if( Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) )
+  {
+    if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD )
+    {
+      pixelBuffer.MultiplyColorByAlpha();
+    }
+  }
+  else
+  {
+    preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  }
+}
+
 } // Anonymous namespace
 
 TextureManager::MaskingData::MaskingData()
@@ -105,13 +121,13 @@ TextureManager::TextureManager()
 }
 
 TextureSet TextureManager::LoadTexture(
-    VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
+    const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
     Dali::SamplingMode::Type samplingMode, const MaskingDataPointer& maskInfo,
     bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect,
     bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
     Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
     AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection,
-    TextureManager::ReloadPolicy reloadPolicy )
+    TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
 {
   TextureSet textureSet;
 
@@ -128,6 +144,7 @@ TextureSet TextureManager::LoadTexture(
       {
         if( elem.textureId == id )
         {
+          textureId = elem.textureId;
           return elem.textureSet;
         }
       }
@@ -142,6 +159,7 @@ TextureSet TextureManager::LoadTexture(
                                        orientationCorrection  );
       if( pixelBuffer )
       {
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
         data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
       }
     }
@@ -152,6 +170,7 @@ TextureSet TextureManager::LoadTexture(
       Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL );
       if( pixelBuffer )
       {
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
         data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
       }
       Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
@@ -190,7 +209,7 @@ TextureSet TextureManager::LoadTexture(
       if( !maskInfo )
       {
         textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS,
-                                 textureObserver, orientationCorrection, reloadPolicy );
+                                 textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad );
       }
       else
       {
@@ -203,10 +222,10 @@ TextureSet TextureManager::LoadTexture(
                                  maskInfo->mCropToMask,
                                  textureObserver,
                                  orientationCorrection,
-                                 reloadPolicy );
+                                 reloadPolicy, preMultiplyOnLoad );
       }
 
-      TextureManager::LoadState loadState = GetTextureState( textureId );
+      TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
       loadingStatus = ( loadState == TextureManager::LOADING );
 
       if( loadState == TextureManager::UPLOADED )
@@ -228,46 +247,51 @@ TextureSet TextureManager::LoadTexture(
 }
 
 TextureManager::TextureId TextureManager::RequestLoad(
-  const VisualUrl&            url,
-  const ImageDimensions       desiredSize,
-  FittingMode::Type           fittingMode,
-  Dali::SamplingMode::Type    samplingMode,
-  const UseAtlas              useAtlas,
-  TextureUploadObserver*      observer,
-  bool                        orientationCorrection,
-  TextureManager::ReloadPolicy reloadPolicy )
+  const VisualUrl&                url,
+  const ImageDimensions           desiredSize,
+  FittingMode::Type               fittingMode,
+  Dali::SamplingMode::Type        samplingMode,
+  const UseAtlas                  useAtlas,
+  TextureUploadObserver*          observer,
+  bool                            orientationCorrection,
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
 {
   return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas,
-                              false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy );
+                              false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
+                              preMultiplyOnLoad );
 }
 
 TextureManager::TextureId TextureManager::RequestLoad(
-  const VisualUrl&             url,
-  TextureId                    maskTextureId,
-  float                        contentScale,
-  const ImageDimensions        desiredSize,
-  FittingMode::Type            fittingMode,
-  Dali::SamplingMode::Type     samplingMode,
-  const UseAtlas               useAtlas,
-  bool                         cropToMask,
-  TextureUploadObserver*       observer,
-  bool                         orientationCorrection,
-  TextureManager::ReloadPolicy reloadPolicy )
+  const VisualUrl&                url,
+  TextureId                       maskTextureId,
+  float                           contentScale,
+  const ImageDimensions           desiredSize,
+  FittingMode::Type               fittingMode,
+  Dali::SamplingMode::Type        samplingMode,
+  const UseAtlas                  useAtlas,
+  bool                            cropToMask,
+  TextureUploadObserver*          observer,
+  bool                            orientationCorrection,
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
 {
   return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas,
-                              cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy );
+                              cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
+                              preMultiplyOnLoad );
 }
 
 TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
 {
   // Use the normal load procedure to get the alpha mask.
+  auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
   return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL,
                               SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL, true,
-                              TextureManager::ReloadPolicy::CACHED );
+                              TextureManager::ReloadPolicy::CACHED, preMultiply );
 }
 
 TextureManager::TextureId TextureManager::RequestLoadInternal(
-  const VisualUrl&               url,
+  const VisualUrl&                url,
   TextureId                       maskTextureId,
   float                           contentScale,
   const ImageDimensions           desiredSize,
@@ -278,17 +302,18 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   StorageType                     storageType,
   TextureUploadObserver*          observer,
   bool                            orientationCorrection,
-  TextureManager::ReloadPolicy    reloadPolicy )
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
 {
   // First check if the requested Texture is cached.
   const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
-                                                maskTextureId );
+                                                maskTextureId, preMultiplyOnLoad );
 
   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 );
+                                      maskTextureId, preMultiplyOnLoad );
 
   // Check if the requested Texture exists in the cache.
   if( cacheIndex != INVALID_CACHE_INDEX )
@@ -308,9 +333,11 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
   {
     // We need a new Texture.
     textureId = GenerateUniqueTextureId();
+    bool preMultiply = ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
     mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(),
                                                   desiredSize, contentScale, fittingMode, samplingMode,
-                                                  false, cropToMask, useAtlas, textureHash, orientationCorrection ) );
+                                                  false, cropToMask, useAtlas, textureHash, orientationCorrection,
+                                                  preMultiply ) );
     cacheIndex = mTextureInfoContainer.size() - 1u;
 
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n",
@@ -363,7 +390,8 @@ TextureManager::TextureId TextureManager::RequestLoadInternal(
         // 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( true, textureInfo.textureId, textureInfo.textureSet,
-                                  textureInfo.useAtlas, textureInfo.atlasRect );
+                                  textureInfo.useAtlas, textureInfo.atlasRect,
+                                  textureInfo.preMultiplied );
       }
       break;
     }
@@ -456,6 +484,31 @@ TextureManager::LoadState TextureManager::GetTextureState( TextureId textureId )
     TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
     loadState = cachedTextureInfo.loadState;
   }
+  else
+  {
+    for( auto&& elem : mExternalTextures )
+    {
+      if( elem.textureId == textureId )
+      {
+        loadState = LoadState::UPLOADED;
+        break;
+      }
+    }
+  }
+  return loadState;
+}
+
+TextureManager::LoadState TextureManager::GetTextureStateInternal( TextureId textureId )
+{
+  LoadState loadState = TextureManager::NOT_STARTED;
+
+  int cacheIndex = GetCacheIndexFromId( textureId );
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+    loadState = cachedTextureInfo.loadState;
+  }
+
   return loadState;
 }
 
@@ -469,6 +522,17 @@ TextureSet TextureManager::GetTextureSet( TextureId textureId )
     TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
     textureSet = cachedTextureInfo.textureSet;
   }
+  else
+  {
+    for( auto&& elem : mExternalTextures )
+    {
+      if( elem.textureId == textureId )
+      {
+        textureSet = elem.textureSet;
+        break;
+      }
+    }
+  }
   return textureSet;
 }
 
@@ -590,7 +654,7 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix
       // wait for the mask to finish loading.
       if( textureInfo.maskTextureId != INVALID_TEXTURE_ID )
       {
-        LoadState maskLoadState = GetTextureState( textureInfo.maskTextureId );
+        LoadState maskLoadState = GetTextureStateInternal( textureInfo.maskTextureId );
         if( maskLoadState == LOADING )
         {
           textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
@@ -669,14 +733,24 @@ void TextureManager::ApplyMask(
   pixelBuffer.ApplyMask( maskPixelBuffer, contentScale, cropToMask );
 }
 
+
 void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo )
 {
   if( textureInfo.useAtlas != USE_ATLAS )
   {
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "  TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId );
 
+    // If the texture doesn't have an alpha channel, can't pre-multiply it.
+    // Ensure that we don't change the load parameter (it's used for hashing), and instead set
+    // the status for use in the observer.
+    auto preMultiply = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD :
+      TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+    PreMultiply( pixelBuffer, preMultiply );
+    textureInfo.preMultiplied = (preMultiply == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
+
     Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(),
                                     pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+
     PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
     texture.Upload( pixelData );
     if ( ! textureInfo.textureSet )
@@ -717,7 +791,8 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
     // 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->textureId, info->textureSet, info->useAtlas, info->atlasRect );
+    observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect,
+                              info->preMultiplied );
     observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
 
     // Get the textureInfo from the container again as it may have been
@@ -764,7 +839,6 @@ int TextureManager::GetCacheIndexFromId( const TextureId textureId )
     }
   }
 
-  DALI_LOG_WARNING( "Cannot locate TextureId: %d\n", textureId );
   return INVALID_CACHE_INDEX;
 }
 
@@ -774,7 +848,8 @@ TextureManager::TextureHash TextureManager::GenerateHash(
   const FittingMode::Type        fittingMode,
   const Dali::SamplingMode::Type samplingMode,
   const UseAtlas                 useAtlas,
-  TextureId                      maskTextureId )
+  TextureId                      maskTextureId,
+  TextureManager::MultiplyOnLoad preMultiplyOnLoad)
 {
   std::string hashTarget( url );
   const size_t urlLength = hashTarget.length();
@@ -808,10 +883,11 @@ TextureManager::TextureHash TextureManager::GenerateHash(
 
   if( maskTextureId != INVALID_TEXTURE_ID )
   {
-    hashTarget.resize( urlLength + sizeof( TextureId ) );
-    TextureId* hashTargetPtr = reinterpret_cast<TextureId*>(&( hashTarget[ urlLength ] ));
+    auto textureIdIndex = hashTarget.length();
+    hashTarget.resize( hashTarget.length() + sizeof( TextureId ) );
+    unsigned char* hashTargetPtr = reinterpret_cast<unsigned char*>(&( hashTarget[ textureIdIndex ] ));
 
-    // Append the hash target to the end of the URL byte by byte:
+    // Append the texture id to the end of the URL byte by byte:
     // (to avoid SIGBUS / alignment issues)
     for( size_t byteIter = 0; byteIter < sizeof( TextureId ); ++byteIter )
     {
@@ -820,6 +896,22 @@ TextureManager::TextureHash TextureManager::GenerateHash(
     }
   }
 
+  auto premultipliedIndex = hashTarget.length();
+  hashTarget.resize( premultipliedIndex + 1 );
+  switch( preMultiplyOnLoad )
+  {
+    case TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD:
+    {
+      hashTarget[ premultipliedIndex ] = 't';
+      break;
+    }
+    case TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY:
+    {
+      hashTarget[ premultipliedIndex ] = 'f';
+      break;
+    }
+  }
+
   return Dali::CalculateHash( hashTarget );
 }
 
@@ -830,7 +922,8 @@ int TextureManager::FindCachedTexture(
   const FittingMode::Type           fittingMode,
   const Dali::SamplingMode::Type    samplingMode,
   const bool                        useAtlas,
-  TextureId                         maskTextureId)
+  TextureId                         maskTextureId,
+  TextureManager::MultiplyOnLoad    preMultiplyOnLoad )
 {
   // Default to an invalid ID, in case we do not find a match.
   int cacheIndex = INVALID_CACHE_INDEX;
@@ -843,11 +936,14 @@ int TextureManager::FindCachedTexture(
     {
       // We have a match, now we check all the original parameters in case of a hash collision.
       TextureInfo& textureInfo( mTextureInfoContainer[i] );
+      auto multiplyOnLoad = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD :
+        TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
       if( ( url == textureInfo.url.GetUrl() ) &&
           ( useAtlas == textureInfo.useAtlas ) &&
           ( maskTextureId == textureInfo.maskTextureId ) &&
           ( size == textureInfo.desiredSize ) &&
+          ( preMultiplyOnLoad ==  multiplyOnLoad ) &&
           ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
             ( fittingMode == textureInfo.fittingMode &&
               samplingMode == textureInfo.samplingMode ) ) )
@@ -883,6 +979,7 @@ void TextureManager::ObserverDestroyed( TextureUploadObserver* observer )
   }
 }
 
+
 TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
 : AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
                      AsyncLoadingInfoContainerType())
index d27b87f..5b6a98e 100644 (file)
@@ -105,14 +105,23 @@ public:
   };
 
   /**
-  * @breif Types of reloading policies
-  */
+   * @brief Types of reloading policies
+   */
   enum class ReloadPolicy
   {
     CACHED = 0,             ///< Loads cached texture if it exists.
     FORCED                  ///< Forces reloading of texture.
   };
 
+  /**
+   * @brief Whether to multiply alpha into color channels on load
+   */
+  enum class MultiplyOnLoad
+  {
+    LOAD_WITHOUT_MULTIPLY = 0, ///< Don't modify the image
+    MULTIPLY_ON_LOAD           ///< Multiply alpha into color channels on load
+  };
+
 public:
 
   struct MaskingData
@@ -140,16 +149,59 @@ public:
 
   // TextureManager Main API:
 
-  TextureSet LoadTexture(VisualUrl& url, Dali::ImageDimensions desiredSize,
-                         Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
-                         const MaskingDataPointer& maskInfo, bool synchronousLoading,
-                         TextureManager::TextureId& textureId, Vector4& textureRect,
-                         bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
-                         Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
-                         AtlasUploadObserver* atlasObserver,
-                         ImageAtlasManagerPtr imageAtlasManager,
-                         bool orientationCorrection,
-                         TextureManager::ReloadPolicy reloadPolicy );
+  /**
+   * @brief Requests an image load of the given URL.
+   *
+   * 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] maskInfo              Mask info structure
+   * @param[in] synchronousLoading    true if the URL should be loaded synchronously
+   * @param[out] textureId,           The textureId of the URL
+   * @param[out] textureRect          The rectangle within the texture atlas that this URL occupies
+   * @param[in,out] atlasingStatus    Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
+   *                                  be loaded, and marked successful, but this will be set to false.
+   *                                  If atlasing succeeds, this will be set to true.
+   * @param[out] loadingStatus        The loading status of the texture
+   * @param[in] wrapModeU             Horizontal Wrap mode
+   * @param[in] wrapModeV             Vertical Wrap mode
+   * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] atlasObserver         This is used if the texture is atlased, and will be called instead of
+   *                                  textureObserver.UploadCompleted
+   * @param[in] imageAtlasManager     The atlas manager to use for atlasing textures
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+   *                                  image has no alpha channel
+   *
+   * @return                          The texture set containing the image, or empty if still loading.
+   */
+
+  TextureSet LoadTexture( const VisualUrl&             url,
+                          Dali::ImageDimensions        desiredSize,
+                          Dali::FittingMode::Type      fittingMode,
+                          Dali::SamplingMode::Type     samplingMode,
+                          const MaskingDataPointer&    maskInfo,
+                          bool                         synchronousLoading,
+                          TextureManager::TextureId&   textureId,
+                          Vector4&                     textureRect,
+                          bool&                        atlasingStatus,
+                          bool&                        loadingStatus,
+                          Dali::WrapMode::Type         wrapModeU,
+                          Dali::WrapMode::Type         wrapModeV,
+                          TextureUploadObserver*       textureObserver,
+                          AtlasUploadObserver*         atlasObserver,
+                          ImageAtlasManagerPtr         imageAtlasManager,
+                          bool                         orientationCorrection,
+                          TextureManager::ReloadPolicy reloadPolicy,
+                          MultiplyOnLoad&              preMultiplyOnLoad );
 
   /**
    * @brief Requests an image load of the given URL.
@@ -169,6 +221,7 @@ public:
    *                                  This is called when an image load completes (or fails).
    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in,out] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
    * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoad( const VisualUrl&                   url,
@@ -178,7 +231,8 @@ public:
                          const UseAtlas                     useAtlasing,
                          TextureUploadObserver*             observer,
                          bool                               orientationCorrection,
-                         TextureManager::ReloadPolicy       reloadPolicy );
+                         TextureManager::ReloadPolicy       reloadPolicy,
+                         MultiplyOnLoad&                    preMultiplyOnLoad );
 
   /**
    * @brief Requests an image load of the given URL, when the texture has
@@ -208,6 +262,8 @@ public:
    *                                  This is called when an image load completes (or fails).
    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the
+   *                                  image has no alpha channel
    * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoad( const VisualUrl&                   url,
@@ -220,7 +276,8 @@ public:
                          bool                               cropToMask,
                          TextureUploadObserver*             observer,
                          bool                               orientationCorrection,
-                         TextureManager::ReloadPolicy       reloadPolicy );
+                         TextureManager::ReloadPolicy       reloadPolicy,
+                         MultiplyOnLoad&                    preMultiplyOnLoad );
 
   /**
    * Requests a masking image to be loaded. This mask is not uploaded to GL,
@@ -302,6 +359,8 @@ private:
    *                                  This is called when an image load completes (or fails).
    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if
+   *                                  there is no alpha
    * @return                          A TextureId to use as a handle to reference this Texture
    */
   TextureId RequestLoadInternal(
@@ -316,8 +375,16 @@ private:
     StorageType                         storageType,
     TextureUploadObserver*              observer,
     bool                                orientationCorrection,
-    TextureManager::ReloadPolicy        reloadPolicy );
+    TextureManager::ReloadPolicy        reloadPolicy,
+    MultiplyOnLoad&                     preMultiplyOnLoad );
 
+  /**
+   * @brief Get the current state of a texture
+   * @param[in] textureId The texture id to query
+   * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
+   * is not valid.
+   */
+  LoadState GetTextureStateInternal( TextureId textureId );
 
   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
 
@@ -337,7 +404,8 @@ private:
                  bool cropToMask,
                  UseAtlas useAtlas,
                  TextureManager::TextureHash hash,
-                 bool orientationCorrection )
+                 bool orientationCorrection,
+                 bool preMultiplyOnLoad )
     : url( url ),
       desiredSize( desiredSize ),
       useSize( desiredSize ),
@@ -354,7 +422,9 @@ private:
       loadSynchronously( loadSynchronously ),
       useAtlas( useAtlas ),
       cropToMask( cropToMask ),
-      orientationCorrection( true )
+      orientationCorrection( true ),
+      preMultiplyOnLoad( preMultiplyOnLoad ),
+      preMultiplied( false )
     {
     }
 
@@ -385,6 +455,8 @@ private:
                                    ///< This is updated to false if atlas is not used
     bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
     bool orientationCorrection:1;  ///< true if the image should be rotated to match exif orientation data
+    bool preMultiplyOnLoad:1;      ///< true if the image's color should be multiplied by it's alpha
+    bool preMultiplied:1;          ///< true if the image's color was multiplied by it's alpha
   };
 
   // Structs:
@@ -523,7 +595,8 @@ private:
   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
                             const FittingMode::Type fittingMode,
                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
-                            TextureId maskTextureId );
+                            TextureId maskTextureId,
+                            MultiplyOnLoad preMultiplyOnLoad);
   /**
    * @brief Looks up a cached texture by its hash.
    * If found, the given parameters are used to check there is no hash-collision.
@@ -543,7 +616,8 @@ private:
     const FittingMode::Type fittingMode,
     const Dali::SamplingMode::Type samplingMode,
     const bool useAtlas,
-    TextureId maskTextureId );
+    TextureId maskTextureId,
+    MultiplyOnLoad preMultiplyOnLoad);
 
 private:
 
@@ -637,7 +711,6 @@ private:  // Member Variables:
   RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders;   ///< The Asynchronous image loaders used to provide all remote async loads
   std::vector< ExternalTextureInfo >            mExternalTextures;     ///< Externally provided textures
   TextureId                                     mCurrentTextureId;     ///< The current value used for the unique Texture Id generation
-
 };
 
 
index d83a89e..a8623f0 100644 (file)
@@ -61,8 +61,10 @@ public:
    * @param[in] textureSet  The TextureSet containing the Texture
    * @param[in] useAtlasing True if atlasing was used (note: this may be different to what was requested)
    * @param[in] atlasRect   If using atlasing, this is the rectangle within the atlas to use.
+   * @param[in] preMultiplied True if the image had pre-multiplied alpha applied
    */
-  virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect ) = 0;
+  virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing,
+                               const Vector4& atlasRect, bool preMultiplied ) = 0;
 
   /**
    * @brief Returns the destruction signal.
index d9a566d..307791b 100644 (file)
@@ -40,8 +40,9 @@ namespace Toolkit
 namespace Internal
 {
 
-VisualFactoryCache::VisualFactoryCache()
-: mSvgRasterizeThread( NULL )
+VisualFactoryCache::VisualFactoryCache( bool preMultiplyOnLoad )
+: mSvgRasterizeThread( NULL ),
+  mPreMultiplyOnLoad( preMultiplyOnLoad )
 {
 }
 
@@ -214,6 +215,16 @@ Image VisualFactoryCache::GetBrokenVisualImage()
   return ResourceImage::New( BROKEN_VISUAL_IMAGE_URL );
 }
 
+void VisualFactoryCache::SetPreMultiplyOnLoad( bool preMultiply )
+{
+  mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactoryCache::GetPreMultiplyOnLoad()
+{
+  return mPreMultiplyOnLoad;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 778a48f..bb4744c 100644 (file)
@@ -47,7 +47,7 @@ typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
 /**
  * Caches shaders and geometries. Owned by VisualFactory.
  */
-class VisualFactoryCache : public RefObject
+class VisualFactoryCache
 {
 public:
 
@@ -108,8 +108,15 @@ public:
 
   /**
    * @brief Constructor
+   *
+   * @param[in] preMultiplyOnLoad True if image visuals should pre-multiply alpha on image load.
    */
-  VisualFactoryCache();
+  VisualFactoryCache( bool preMultiplyOnLoad );
+
+  /**
+   * @brief Destructor
+   */
+  ~VisualFactoryCache();
 
   /**
    * Request geometry of the given type.
@@ -156,6 +163,16 @@ public:
    */
   static Image GetBrokenVisualImage();
 
+  /**
+   * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+   */
+  void SetPreMultiplyOnLoad( bool preMultiply );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+   */
+  bool GetPreMultiplyOnLoad();
+
 public:
   /**
    * Get the image atlas manager.
@@ -191,11 +208,6 @@ private: // for svg rasterization thread
 protected:
 
   /**
-   * A reference counted object may only be deleted by calling Unreference()
-   */
-  virtual ~VisualFactoryCache();
-
-  /**
    * Undefined copy constructor.
    */
   VisualFactoryCache(const VisualFactoryCache&);
@@ -213,6 +225,7 @@ private:
   TextureManager       mTextureManager;
   NPatchLoader         mNPatchLoader;
   SvgRasterizeThread*  mSvgRasterizeThread;
+  bool                 mPreMultiplyOnLoad;
 };
 
 } // namespace Internal
index c368580..90bb937 100644 (file)
@@ -71,7 +71,8 @@ DALI_TYPE_REGISTRATION_END()
 } // namespace
 
 VisualFactory::VisualFactory( bool debugEnabled )
-:mDebugEnabled( debugEnabled )
+: mDebugEnabled( debugEnabled ),
+  mPreMultiplyOnLoad( true )
 {
 }
 
@@ -81,12 +82,6 @@ VisualFactory::~VisualFactory()
 
 Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& propertyMap )
 {
-  // Create factory cache if it hasn't already been
-  if( !mFactoryCache )
-  {
-    mFactoryCache = new VisualFactoryCache();
-  }
-
   Visual::BasePtr visualPtr;
 
   Property::Value* typeValue = propertyMap.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE );
@@ -100,19 +95,19 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
   {
     case Toolkit::Visual::BORDER:
     {
-      visualPtr = BorderVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = BorderVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
     case Toolkit::Visual::COLOR:
     {
-      visualPtr = ColorVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = ColorVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
     case Toolkit::Visual::GRADIENT:
     {
-      visualPtr = GradientVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = GradientVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
@@ -132,22 +127,22 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
             {
               case VisualUrl::N_PATCH:
               {
-                visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+                visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl, propertyMap );
                 break;
               }
               case VisualUrl::SVG:
               {
-                visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+                visualPtr = SvgVisual::New( GetFactoryCache(), visualUrl, propertyMap );
                 break;
               }
               case VisualUrl::GIF:
               {
-                visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+                visualPtr = AnimatedImageVisual::New( GetFactoryCache(), visualUrl, propertyMap );
                 break;
               }
               case VisualUrl::REGULAR_IMAGE:
               {
-                visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+                visualPtr = ImageVisual::New( GetFactoryCache(), visualUrl, propertyMap );
                 break;
               }
             }
@@ -158,7 +153,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
           Property::Array* array = imageURLValue->GetArray();
           if( array )
           {
-            visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap );
+            visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap );
           }
         }
       }
@@ -167,25 +162,25 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
 
     case Toolkit::Visual::MESH:
     {
-      visualPtr = MeshVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = MeshVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
     case Toolkit::Visual::PRIMITIVE:
     {
-      visualPtr = PrimitiveVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = PrimitiveVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
     case Toolkit::Visual::WIREFRAME:
     {
-      visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = WireframeVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
     case Toolkit::Visual::TEXT:
     {
-      visualPtr = TextVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = TextVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
 
@@ -195,7 +190,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
       std::string imageUrl;
       if( imageURLValue && imageURLValue->Get( imageUrl ) )
       {
-        visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+        visualPtr = NPatchVisual::New( GetFactoryCache(), imageUrl, propertyMap );
       }
       break;
     }
@@ -206,7 +201,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
       std::string imageUrl;
       if( imageURLValue && imageURLValue->Get( imageUrl ) )
       {
-        visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+        visualPtr = SvgVisual::New( GetFactoryCache(), imageUrl, propertyMap );
       }
       break;
     }
@@ -219,14 +214,14 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
       {
         if( imageURLValue->Get( imageUrl ) )
         {
-          visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+          visualPtr = AnimatedImageVisual::New( GetFactoryCache(), imageUrl, propertyMap );
         }
         else
         {
           Property::Array* array = imageURLValue->GetArray();
           if( array )
           {
-            visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap );
+            visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap );
           }
         }
       }
@@ -235,7 +230,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
 
     case Toolkit::DevelVisual::ANIMATED_GRADIENT:
     {
-      visualPtr = AnimatedGradientVisual::New( *( mFactoryCache.Get() ), propertyMap );
+      visualPtr = AnimatedGradientVisual::New( GetFactoryCache(), propertyMap );
       break;
     }
   }
@@ -248,7 +243,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
   if( mDebugEnabled && visualType !=  Toolkit::DevelVisual::WIREFRAME )
   {
     //Create a WireframeVisual if we have debug enabled
-    visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr, propertyMap );
+    visualPtr = WireframeVisual::New(GetFactoryCache(), visualPtr, propertyMap );
   }
 
   return Toolkit::Visual::Base( visualPtr.Get() );
@@ -256,11 +251,6 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property
 
 Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
 {
-  if( !mFactoryCache )
-  {
-    mFactoryCache = new VisualFactoryCache();
-  }
-
   Visual::BasePtr visualPtr;
 
   if( image )
@@ -268,18 +258,18 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
     NinePatchImage npatchImage = NinePatchImage::DownCast( image );
     if( npatchImage )
     {
-      visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), npatchImage );
+      visualPtr = NPatchVisual::New( GetFactoryCache(), npatchImage );
     }
     else
     {
-      visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), image );
+      visualPtr = ImageVisual::New(GetFactoryCache(), image );
     }
   }
 
   if( mDebugEnabled )
   {
     //Create a WireframeVisual if we have debug enabled
-    visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr );
+    visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr );
   }
 
   return Toolkit::Visual::Base( visualPtr.Get() );
@@ -287,11 +277,6 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
 
 Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimensions size )
 {
-  if( !mFactoryCache )
-  {
-    mFactoryCache = new VisualFactoryCache();
-  }
-
   Visual::BasePtr visualPtr;
 
   if( !url.empty() )
@@ -302,22 +287,22 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image
     {
       case VisualUrl::N_PATCH:
       {
-        visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl );
+        visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl );
         break;
       }
       case VisualUrl::SVG:
       {
-        visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl );
+        visualPtr = SvgVisual::New( GetFactoryCache(), visualUrl );
         break;
       }
       case VisualUrl::GIF:
       {
-        visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl );
+        visualPtr = AnimatedImageVisual::New( GetFactoryCache(), visualUrl );
         break;
       }
       case VisualUrl::REGULAR_IMAGE:
       {
-        visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, size );
+        visualPtr = ImageVisual::New(GetFactoryCache(), visualUrl, size );
         break;
       }
     }
@@ -326,19 +311,38 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image
   if( mDebugEnabled )
   {
     //Create a WireframeVisual if we have debug enabled
-    visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr );
+    visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr );
   }
 
   return Toolkit::Visual::Base( visualPtr.Get() );
 }
 
+void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply )
+{
+  if( mPreMultiplyOnLoad != preMultiply )
+  {
+    GetFactoryCache().SetPreMultiplyOnLoad( preMultiply );
+  }
+  mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactory::GetPreMultiplyOnLoad() const
+{
+  return mPreMultiplyOnLoad;
+}
+
 Internal::TextureManager& VisualFactory::GetTextureManager()
 {
+  return GetFactoryCache().GetTextureManager();
+}
+
+Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
+{
   if( !mFactoryCache )
   {
-    mFactoryCache = new VisualFactoryCache();
+    mFactoryCache = std::unique_ptr<VisualFactoryCache>( new VisualFactoryCache( mPreMultiplyOnLoad ) );
   }
-  return mFactoryCache->GetTextureManager();
+  return *mFactoryCache;
 }
 
 } // namespace Internal
index 257b03c..999a0c4 100644 (file)
@@ -35,7 +35,6 @@ namespace Internal
 {
 
 class VisualFactoryCache;
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
 
 /**
  * @copydoc Toolkit::VisualFactory
@@ -52,21 +51,31 @@ public:
   VisualFactory( bool debugEnabled );
 
   /**
-   * @copydoc Toolkit::RenderFactory::CreateVisual( const Property::Map& )
+   * @copydoc Toolkit::VisualFactory::CreateVisual( const Property::Map& )
    */
   Toolkit::Visual::Base CreateVisual( const Property::Map& propertyMap );
 
   /**
-   * @copydoc Toolkit::RenderFactory::CreateVisual( const Image& )
+   * @copydoc Toolkit::VisualFactory::CreateVisual( const Image& )
    */
   Toolkit::Visual::Base CreateVisual( const Image& image );
 
   /**
-   * @copydoc Toolkit::RenderFactory::CreateVisual( const std::string&, ImageDimensions )
+   * @copydoc Toolkit::VisualFactory::CreateVisual( const std::string&, ImageDimensions )
    */
   Toolkit::Visual::Base CreateVisual( const std::string& image, ImageDimensions size );
 
   /**
+   * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+   */
+  void SetPreMultiplyOnLoad( bool preMultiply );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+   */
+  bool GetPreMultiplyOnLoad() const;
+
+  /**
    * @return the reference to texture manager
    */
   Internal::TextureManager& GetTextureManager();
@@ -79,21 +88,19 @@ protected:
   virtual ~VisualFactory();
 
 private:
-
   /**
-   * Undefined copy constructor.
+   * Get the factory cache, creating it if necessary.
    */
-  VisualFactory(const VisualFactory&);
+  Internal::VisualFactoryCache& GetFactoryCache();
 
-  /**
-   * Undefined assignment operator.
-   */
-  VisualFactory& operator=(const VisualFactory& rhs);
+  VisualFactory(const VisualFactory&) = delete;
 
-private:
+  VisualFactory& operator=(const VisualFactory& rhs) = delete;
 
-  VisualFactoryCachePtr   mFactoryCache;
-  bool                    mDebugEnabled;
+private:
+  std::unique_ptr<VisualFactoryCache> mFactoryCache;
+  bool                                mDebugEnabled:1;
+  bool                                mPreMultiplyOnLoad:1; ///< Local store for this flag
 };
 
 /**
index 9e889cb..079141d 100644 (file)
@@ -72,6 +72,9 @@ const char * const PREMULTIPLIED_ALPHA( "premultipliedAlpha" );
 const char * const MIX_COLOR( "mixColor" );
 const char * const OPACITY( "opacity" );
 
+// Color visual
+const char * const RENDER_IF_TRANSPARENT_NAME( "renderIfTransparent" );
+
 // Image visual
 const char * const IMAGE_URL_NAME( "url" );
 const char * const ATLAS_RECT_UNIFORM_NAME( "uAtlasRect" );
index eb0b617..1a73da9 100644 (file)
@@ -58,6 +58,9 @@ extern const char * const PREMULTIPLIED_ALPHA;
 extern const char * const MIX_COLOR;
 extern const char * const OPACITY;
 
+// Color visual
+extern const char * const RENDER_IF_TRANSPARENT_NAME;
+
 // Image visual
 extern const char * const IMAGE_URL_NAME;
 extern const char * const ATLAS_RECT_UNIFORM_NAME;
index 907b428..b1f5f3e 100644 (file)
@@ -234,7 +234,7 @@ bool VisualUrl::IsLocalResource() const
   return mLocation == VisualUrl::LOCAL;
 }
 
-std::string VisualUrl::GetLocation()
+std::string VisualUrl::GetLocation() const
 {
   const auto location = mUrl.find( "://" );
   if( std::string::npos != location )
index b261813..aac605c 100644 (file)
@@ -107,7 +107,7 @@ public:
   /**
    * @return the location part of the url
    */
-  std::string GetLocation();
+  std::string GetLocation() const;
 
   /**
    * Helper to create a URL of type TEXTURE
index 47a12b1..49064a8 100755 (executable)
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
 #include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
 #include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
-#include <dali-toolkit/public-api/visuals/visual-properties.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
-#include <dali-toolkit/public-api/align-enumerations.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 
 namespace Dali
@@ -61,6 +62,30 @@ Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CO
 #endif
 
 /**
+ * @brief Replace the background visual if it's a color visual with the renderIfTransparent property set as required.
+ * @param[in] controlImpl The control implementation
+ * @param[in] renderIfTransaparent Whether we should render if the color is transparent
+ */
+void ChangeBackgroundColorVisual( Control& controlImpl, bool renderIfTransparent )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+
+  Toolkit::Visual::Base backgroundVisual = controlDataImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( backgroundVisual )
+  {
+    Property::Map map;
+    backgroundVisual.CreatePropertyMap( map );
+    Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE );
+    if( typeValue && typeValue->Get< int >() == Toolkit::Visual::COLOR )
+    {
+      // Only change it if it's a color visual
+      map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = renderIfTransparent;
+      controlImpl.SetBackground( map );
+    }
+  }
+}
+
+/**
  * @brief Creates a clipping renderer if required.
  * (EG. If no renders exist and clipping is enabled).
  * @param[in] controlImpl The control implementation.
@@ -72,13 +97,34 @@ void CreateClippingRenderer( Control& controlImpl )
   int clippingMode = ClippingMode::DISABLED;
   if( self.GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) )
   {
-    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
-
-    if( ( clippingMode == ClippingMode::CLIP_CHILDREN ) &&
-        controlDataImpl.mVisuals.Empty() &&
-        ( self.GetRendererCount() == 0u ) )
+    switch( clippingMode )
     {
-      controlImpl.SetBackgroundColor( Color::TRANSPARENT );
+      case ClippingMode::CLIP_CHILDREN:
+      {
+        if( self.GetRendererCount() == 0u )
+        {
+          Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+          if( controlDataImpl.mVisuals.Empty() )
+          {
+            controlImpl.SetBackgroundColor( Color::TRANSPARENT );
+          }
+          else
+          {
+            // We have visuals, check if we've set the background and re-create it to
+            // render even if transparent (only if it's a color visual)
+            ChangeBackgroundColorVisual( controlImpl, true );
+          }
+        }
+        break;
+      }
+
+      case ClippingMode::DISABLED:
+      case ClippingMode::CLIP_TO_BOUNDING_BOX:
+      {
+        // If we have a background visual, check if it's a color visual and remove the render if transparent flag
+        ChangeBackgroundColorVisual( controlImpl, false );
+        break;
+      }
     }
   }
 }
@@ -168,6 +214,14 @@ void Control::SetBackgroundColor( const Vector4& color )
   map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::COLOR;
   map[ Toolkit::ColorVisual::Property::MIX_COLOR ] = color;
 
+  int clippingMode = ClippingMode::DISABLED;
+  if( ( Self().GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) ) &&
+      ( clippingMode == ClippingMode::CLIP_CHILDREN ) )
+  {
+    // If clipping-mode is set to CLIP_CHILDREN, then force visual to add the render even if transparent
+    map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = true;
+  }
+
   SetBackground( map );
 }
 
index d2c2e3f..5a230f0 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 5;
+const unsigned int TOOLKIT_MICRO_VERSION = 6;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index b08ff39..3988e6c 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    1.3.5
+Version:    1.3.6
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT