[4.0] Added automatic premultiplication of image visual images 96/165896/1
authorDavid Steele <david.steele@samsung.com>
Wed, 3 Jan 2018 16:20:19 +0000 (16:20 +0000)
committerdongsug.song <dongsug.song@samsung.com>
Thu, 4 Jan 2018 21:49:27 +0000 (06:49 +0900)
To prevent scaling quality issues, image visual images are pre-multiplied after loading.
By default, this is on, but it can be turned off via a new API in VisualFactory.

Conflicts:
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.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
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/image/image-visual.cpp
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-impl.h

Change-Id: Id1606e156f2d31d858bb4ddc65cbf97ed3efba5c
Signed-off-by: David Steele <david.steele@samsung.com>
17 files changed:
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp [changed mode: 0644->0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp [changed mode: 0644->0755]
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp [changed mode: 0644->0755]
dali-toolkit/devel-api/visual-factory/visual-factory.h [changed mode: 0644->0755]
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
dali-toolkit/internal/visuals/image/image-visual.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/image/image-visual.h
dali-toolkit/internal/visuals/texture-manager-impl.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/texture-manager-impl.h [changed mode: 0644->0755]
dali-toolkit/internal/visuals/texture-upload-observer.h
dali-toolkit/internal/visuals/visual-factory-cache.h [changed mode: 0644->0755]
dali-toolkit/internal/visuals/visual-factory-impl.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/visual-factory-impl.h [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 12a25f7..bd88e76
@@ -28,13 +28,11 @@ namespace Toolkit
 namespace Internal
 {
 
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
-
 DummyVisualPtr DummyVisual::New( const Property::Map& properties )
 {
-  VisualFactoryCachePtr factoryCache = new VisualFactoryCache(false);
+  VisualFactoryCache* factoryCache = new VisualFactoryCache(false);
 
-  DummyVisualPtr dummyVisualPtr( new DummyVisual( *( factoryCache.Get() ) ) );
+  DummyVisualPtr dummyVisualPtr( new DummyVisual( *factoryCache ) );
 
   return dummyVisualPtr;
 }
old mode 100644 (file)
new mode 100755 (executable)
index d240930..ebada51
@@ -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(),
@@ -63,7 +64,7 @@ int UtcTextureManagerRequestLoad(void)
     &observer,
     true,
     TextureManager::ReloadPolicy::CACHED,
-    TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY );
+    preMultiply);
 
   const VisualUrl& url = textureManager.GetVisualUrl( textureId );
 
old mode 100644 (file)
new mode 100755 (executable)
index cd29162..b4d7653
@@ -261,6 +261,63 @@ int UtcDaliImageVisualNoPremultipliedAlpha01(void)
 }
 
 
+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 );
+  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 UtcDaliImageVisualRemoteImageLoad(void)
 {
   ToolkitTestApplication application;
old mode 100644 (file)
new mode 100755 (executable)
index 8571378..856360b
@@ -122,20 +122,17 @@ public:
    *
    * The default is to enable pre-multiplication on load.
    *
-   * Applications that have assets with pre-multiplied alpha already applied should
-   * turn this option off.
+   * 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.
+   * @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.
+   * @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.
+   * @return True if loaded images have pre-multiplied alpha applied on load, false otherwise.
    */
   bool GetPreMultiplyOnLoad() const;
 
old mode 100644 (file)
new mode 100755 (executable)
index f1b3411..b1713d2
@@ -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,
@@ -121,7 +122,7 @@ void FixedImageCache::LoadBatch()
       atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
       Dali::WrapMode::Type::DEFAULT, this,
       atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
-      TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY );
+      preMultiply );
 
     if( loadingStatus == false )  // not loading, means it's already ready.
     {
@@ -165,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;
old mode 100644 (file)
new mode 100755 (executable)
index 58f1410..ed61adb
@@ -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, TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY );
+        atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply );
     }
 
     mFrameIndex += batchSize;
old mode 100644 (file)
new mode 100755 (executable)
index 80deb58..37c7a7d
@@ -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,
@@ -156,7 +157,7 @@ void RollingImageCache::LoadBatch()
       atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
       Dali::WrapMode::Type::DEFAULT, this,
       atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
-      TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY );
+      preMultiply );
 
     mRequestingLoad = false;
   }
@@ -201,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 06240c6..07db411 100644 (file)
@@ -111,7 +111,8 @@ protected:
     int32_t        textureId,
     TextureSet     textureSet,
     bool           useAtlasing,
-    const Vector4& atlasRect );
+    const Vector4& atlasRect,
+    bool           preMultiplied ) override;
 
 private:
   /**
old mode 100644 (file)
new mode 100755 (executable)
index 84c221c..8108471
@@ -759,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;
@@ -790,7 +789,7 @@ void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& t
                                          mWrapModeV, textureObserver, atlasUploadObserver, atlasManager,
                                          mOrientationCorrection, forceReload, preMultiplyOnLoad);
 
-  if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
+  if( textures && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
   {
     EnablePreMultipliedAlpha( true );
   }
@@ -1096,7 +1095,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();
@@ -1108,6 +1107,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 e3b8e61..7b4ac56 100644 (file)
@@ -266,7 +266,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
@@ -274,7 +274,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:
 
old mode 100644 (file)
new mode 100755 (executable)
index 16d8d95..7f62d22
@@ -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::MultiplyOnLoad preMultiplyOnLoad )
+    TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
 {
   TextureSet textureSet;
 
@@ -143,11 +159,7 @@ TextureSet TextureManager::LoadTexture(
                                        orientationCorrection  );
       if( pixelBuffer )
       {
-        if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD )
-        {
-          pixelBuffer.MultiplyColorByAlpha();
-        }
-
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
         data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
       }
     }
@@ -158,10 +170,7 @@ TextureSet TextureManager::LoadTexture(
       Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL );
       if( pixelBuffer )
       {
-        if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
-        {
-          pixelBuffer.MultiplyColorByAlpha();
-        }
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
         data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
       }
       Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
@@ -238,60 +247,63 @@ 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,
-  TextureManager::MultiplyOnLoad preMultiplyOnLoad )
+  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, preMultiplyOnLoad );
+                              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,
-  TextureManager::MultiplyOnLoad preMultiplyOnLoad )
+  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, preMultiplyOnLoad );
+                              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::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY);
+                              TextureManager::ReloadPolicy::CACHED, preMultiply );
 }
 
 TextureManager::TextureId TextureManager::RequestLoadInternal(
-  const VisualUrl&               url,
-  TextureId                      maskTextureId,
-  float                          contentScale,
-  const ImageDimensions          desiredSize,
-  FittingMode::Type              fittingMode,
-  Dali::SamplingMode::Type       samplingMode,
-  UseAtlas                       useAtlas,
-  bool                           cropToMask,
-  StorageType                    storageType,
-  TextureUploadObserver*         observer,
-  bool                           orientationCorrection,
-  TextureManager::ReloadPolicy   reloadPolicy,
-  TextureManager::MultiplyOnLoad preMultiplyOnLoad)
+  const VisualUrl&                url,
+  TextureId                       maskTextureId,
+  float                           contentScale,
+  const ImageDimensions           desiredSize,
+  FittingMode::Type               fittingMode,
+  Dali::SamplingMode::Type        samplingMode,
+  UseAtlas                        useAtlas,
+  bool                            cropToMask,
+  StorageType                     storageType,
+  TextureUploadObserver*          observer,
+  bool                            orientationCorrection,
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
 {
   // First check if the requested Texture is cached.
   const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
@@ -321,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, preMultiplyOnLoad ) );
+                                                  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",
@@ -376,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;
     }
@@ -718,18 +733,23 @@ 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() );
-    if( textureInfo.preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD )
-    {
-      pixelBuffer.MultiplyColorByAlpha();
-    }
 
     PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
     texture.Upload( pixelData );
@@ -771,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
@@ -877,8 +898,19 @@ TextureManager::TextureHash TextureManager::GenerateHash(
 
   auto premultipliedIndex = hashTarget.length();
   hashTarget.resize( premultipliedIndex + 1 );
-  char* preMultPtr = &( hashTarget[ premultipliedIndex ] );
-  *preMultPtr = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? 't':'f';
+  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 );
 }
@@ -904,12 +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 == textureInfo.preMultiplyOnLoad ) &&
+          ( preMultiplyOnLoad ==  multiplyOnLoad ) &&
           ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
             ( fittingMode == textureInfo.fittingMode &&
               samplingMode == textureInfo.samplingMode ) ) )
old mode 100644 (file)
new mode 100755 (executable)
index 1dc9d56..5b6a98e
@@ -149,17 +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,
-                         MultiplyOnLoad preMultiplyOnLoad );
+  /**
+   * @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.
@@ -179,7 +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] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha
+   * @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,
@@ -190,7 +232,7 @@ public:
                          TextureUploadObserver*             observer,
                          bool                               orientationCorrection,
                          TextureManager::ReloadPolicy       reloadPolicy,
-                         MultiplyOnLoad                     preMultiplyOnLoad );
+                         MultiplyOnLoad&                    preMultiplyOnLoad );
 
   /**
    * @brief Requests an image load of the given URL, when the texture has
@@ -220,7 +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
+   * @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,
@@ -234,7 +277,7 @@ public:
                          TextureUploadObserver*             observer,
                          bool                               orientationCorrection,
                          TextureManager::ReloadPolicy       reloadPolicy,
-                         MultiplyOnLoad                     preMultiplyOnLoad );
+                         MultiplyOnLoad&                    preMultiplyOnLoad );
 
   /**
    * Requests a masking image to be loaded. This mask is not uploaded to GL,
@@ -316,7 +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
+   * @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(
@@ -332,7 +376,7 @@ private:
     TextureUploadObserver*              observer,
     bool                                orientationCorrection,
     TextureManager::ReloadPolicy        reloadPolicy,
-    MultiplyOnLoad                      preMultiplyOnLoad );
+    MultiplyOnLoad&                     preMultiplyOnLoad );
 
   /**
    * @brief Get the current state of a texture
@@ -361,7 +405,7 @@ private:
                  UseAtlas useAtlas,
                  TextureManager::TextureHash hash,
                  bool orientationCorrection,
-                 MultiplyOnLoad preMultiplyOnLoad )
+                 bool preMultiplyOnLoad )
     : url( url ),
       desiredSize( desiredSize ),
       useSize( desiredSize ),
@@ -379,7 +423,8 @@ private:
       useAtlas( useAtlas ),
       cropToMask( cropToMask ),
       orientationCorrection( true ),
-      preMultiplyOnLoad( preMultiplyOnLoad )
+      preMultiplyOnLoad( preMultiplyOnLoad ),
+      preMultiplied( false )
     {
     }
 
@@ -410,7 +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
-    MultiplyOnLoad preMultiplyOnLoad; ///< true if the image's color should be multiplied by it's alpha
+    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:
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.
old mode 100644 (file)
new mode 100755 (executable)
index cff49ac..bb4744c
@@ -47,7 +47,7 @@ typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
 /**
  * Caches shaders and geometries. Owned by VisualFactory.
  */
-class VisualFactoryCache : public RefObject
+class VisualFactoryCache
 {
 public:
 
@@ -114,6 +114,11 @@ public:
   VisualFactoryCache( bool preMultiplyOnLoad );
 
   /**
+   * @brief Destructor
+   */
+  ~VisualFactoryCache();
+
+  /**
    * Request geometry of the given type.
    * @return The geometry of the required type if it exist in the cache. Otherwise, an empty handle is returned.
    */
@@ -203,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&);
old mode 100644 (file)
new mode 100755 (executable)
index cb3fb9d..90bb937
@@ -340,9 +340,9 @@ Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
 {
   if( !mFactoryCache )
   {
-    mFactoryCache = new VisualFactoryCache( mPreMultiplyOnLoad );
+    mFactoryCache = std::unique_ptr<VisualFactoryCache>( new VisualFactoryCache( mPreMultiplyOnLoad ) );
   }
-  return *(mFactoryCache.Get());
+  return *mFactoryCache;
 }
 
 } // namespace Internal
old mode 100644 (file)
new mode 100755 (executable)
index c0a7d2f..999a0c4
@@ -35,7 +35,6 @@ namespace Internal
 {
 
 class VisualFactoryCache;
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
 
 /**
  * @copydoc Toolkit::VisualFactory
@@ -99,10 +98,9 @@ private:
   VisualFactory& operator=(const VisualFactory& rhs) = delete;
 
 private:
-
-  VisualFactoryCachePtr   mFactoryCache;
-  bool                    mDebugEnabled:1;
-  bool                    mPreMultiplyOnLoad:1; ///< Local store for this flag ( as mFactoryCache is lazy laoded )
+  std::unique_ptr<VisualFactoryCache> mFactoryCache;
+  bool                                mDebugEnabled:1;
+  bool                                mPreMultiplyOnLoad:1; ///< Local store for this flag
 };
 
 /**