Merge "Added automatic premultiplication of image visual images" into devel/master
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 4 Jan 2018 22:00:39 +0000 (22:00 +0000)
committerGerrit Code Review <gerrit@review.ap-northeast-2.compute.internal>
Thu, 4 Jan 2018 22:00:39 +0000 (22:00 +0000)
19 files changed:
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
dali-toolkit/devel-api/visual-factory/visual-factory.cpp
dali-toolkit/devel-api/visual-factory/visual-factory.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/rolling-gif-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/image/image-visual.h
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-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

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 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 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 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);
index 3764500..b1713d2 100644 (file)
@@ -113,6 +113,7 @@ void FixedImageCache::LoadBatch()
     AtlasUploadObserver* atlasObserver = nullptr;
     ImageAtlasManagerPtr imageAtlasManager = nullptr;
     Vector4 textureRect;
+    auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
     mTextureManager.LoadTexture(
       url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
@@ -120,7 +121,8 @@ void FixedImageCache::LoadBatch()
       synchronousLoading, mImageUrls[ mUrlIndex ].mTextureId, textureRect,
       atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
       Dali::WrapMode::Type::DEFAULT, this,
-      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+      preMultiply );
 
     if( loadingStatus == false )  // not loading, means it's already ready.
     {
@@ -164,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 b9b2ddb..570b2d7 100644 (file)
@@ -95,7 +95,8 @@ protected:
     int32_t        textureId,
     TextureSet     textureSet,
     bool           useAtlasing,
-    const Vector4& atlasRect );
+    const Vector4& atlasRect,
+    bool           premultiplied) override;
 
 private:
   std::vector<UrlStore>& mImageUrls;
index 5922f74..ed61adb 100644 (file)
@@ -147,6 +147,7 @@ void RollingGifImageCache::LoadBatch()
       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,
@@ -154,7 +155,7 @@ void RollingGifImageCache::LoadBatch()
         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 );
+        atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply );
     }
 
     mFrameIndex += batchSize;
index 62599e5..37c7a7d 100644 (file)
@@ -148,6 +148,7 @@ void RollingImageCache::LoadBatch()
     AtlasUploadObserver* atlasObserver = nullptr;
     ImageAtlasManagerPtr imageAtlasManager = nullptr;
     Vector4 textureRect;
+    auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
     mTextureManager.LoadTexture(
       url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
@@ -155,7 +156,8 @@ void RollingImageCache::LoadBatch()
       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 );
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+      preMultiply );
 
     mRequestingLoad = false;
   }
@@ -200,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 b1fcce3..76a79ec 100644 (file)
@@ -111,7 +111,8 @@ protected:
     int32_t        textureId,
     TextureSet     textureSet,
     bool           useAtlasing,
-    const Vector4& atlasRect );
+    const Vector4& atlasRect,
+    bool           preMultiplied ) override;
 
 private:
   /**
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 6b31322..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()
@@ -111,7 +127,7 @@ TextureSet TextureManager::LoadTexture(
     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;
 
@@ -143,6 +159,7 @@ TextureSet TextureManager::LoadTexture(
                                        orientationCorrection  );
       if( pixelBuffer )
       {
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
         data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
       }
     }
@@ -153,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(),
@@ -191,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
       {
@@ -204,7 +222,7 @@ TextureSet TextureManager::LoadTexture(
                                  maskInfo->mCropToMask,
                                  textureObserver,
                                  orientationCorrection,
-                                 reloadPolicy );
+                                 reloadPolicy, preMultiplyOnLoad );
       }
 
       TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
@@ -229,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,
@@ -279,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 )
@@ -309,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",
@@ -364,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;
     }
@@ -706,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 )
@@ -754,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
@@ -810,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();
@@ -844,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 )
     {
@@ -856,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 );
 }
 
@@ -866,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;
@@ -879,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 ) ) )
@@ -919,6 +979,7 @@ void TextureManager::ObserverDestroyed( TextureUploadObserver* observer )
   }
 }
 
+
 TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
 : AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
                      AsyncLoadingInfoContainerType())
index 8d46f04..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(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 );
+  /**
+   * @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,7 +375,8 @@ private:
     StorageType                         storageType,
     TextureUploadObserver*              observer,
     bool                                orientationCorrection,
-    TextureManager::ReloadPolicy        reloadPolicy );
+    TextureManager::ReloadPolicy        reloadPolicy,
+    MultiplyOnLoad&                     preMultiplyOnLoad );
 
   /**
    * @brief Get the current state of a texture
@@ -344,7 +404,8 @@ private:
                  bool cropToMask,
                  UseAtlas useAtlas,
                  TextureManager::TextureHash hash,
-                 bool orientationCorrection )
+                 bool orientationCorrection,
+                 bool preMultiplyOnLoad )
     : url( url ),
       desiredSize( desiredSize ),
       useSize( desiredSize ),
@@ -361,7 +422,9 @@ private:
       loadSynchronously( loadSynchronously ),
       useAtlas( useAtlas ),
       cropToMask( cropToMask ),
-      orientationCorrection( true )
+      orientationCorrection( true ),
+      preMultiplyOnLoad( preMultiplyOnLoad ),
+      preMultiplied( false )
     {
     }
 
@@ -392,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:
@@ -530,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.
@@ -550,7 +616,8 @@ private:
     const FittingMode::Type fittingMode,
     const Dali::SamplingMode::Type samplingMode,
     const bool useAtlas,
-    TextureId maskTextureId );
+    TextureId maskTextureId,
+    MultiplyOnLoad preMultiplyOnLoad);
 
 private:
 
@@ -644,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
 };
 
 /**