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.
Change-Id: I53757be33894effdd61b719631fb79527e8a4fbe
Signed-off-by: David Steele <david.steele@samsung.com>
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;
}
{
}
- 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;
TestObserver observer;
std::string filename("image.png");
-
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
TextureManager::TextureId textureId = textureManager.RequestLoad(
filename,
ImageDimensions(),
TextureManager::NO_ATLAS,
&observer,
true,
- TextureManager::ReloadPolicy::CACHED );
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
const VisualUrl& url = textureManager.GetVisualUrl( textureId );
VisualFactory factory = VisualFactory::Get();
DALI_TEST_CHECK( factory );
+ factory.SetPreMultiplyOnLoad( true );
Property::Map propertyMap;
propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
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 );
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 );
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
*/
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);
AtlasUploadObserver* atlasObserver = nullptr;
ImageAtlasManagerPtr imageAtlasManager = nullptr;
Vector4 textureRect;
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
mTextureManager.LoadTexture(
url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
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.
{
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect )
+ const Vector4& atlasRect,
+ bool preMultiplied)
{
bool frontFrameReady = IsFrontReady();
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect );
+ const Vector4& atlasRect,
+ bool premultiplied) override;
private:
std::vector<UrlStore>& mImageUrls;
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,
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;
AtlasUploadObserver* atlasObserver = nullptr;
ImageAtlasManagerPtr imageAtlasManager = nullptr;
Vector4 textureRect;
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
mTextureManager.LoadTexture(
url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
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;
}
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;
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect );
+ const Vector4& atlasRect,
+ bool preMultiplied ) override;
private:
/**
//Register transform properties
mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+ if( IsPreMultipliedAlphaEnabled() )
+ {
+ EnablePreMultipliedAlpha( true );
+ }
}
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;
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
{
// 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();
{
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
* 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
* 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:
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()
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;
orientationCorrection );
if( pixelBuffer )
{
+ PreMultiply( pixelBuffer, preMultiplyOnLoad );
data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
}
}
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(),
if( !maskInfo )
{
textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS,
- textureObserver, orientationCorrection, reloadPolicy );
+ textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad );
}
else
{
maskInfo->mCropToMask,
textureObserver,
orientationCorrection,
- reloadPolicy );
+ reloadPolicy, preMultiplyOnLoad );
}
TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
}
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,
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 )
{
// 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",
// 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;
}
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 )
// 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
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();
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 )
{
}
}
+ 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 );
}
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;
{
// 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 ) ) )
}
}
+
TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
: AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
AsyncLoadingInfoContainerType())
};
/**
- * @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
// 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.
* 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,
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
* 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,
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,
* 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(
StorageType storageType,
TextureUploadObserver* observer,
bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy );
+ TextureManager::ReloadPolicy reloadPolicy,
+ MultiplyOnLoad& preMultiplyOnLoad );
/**
* @brief Get the current state of a texture
bool cropToMask,
UseAtlas useAtlas,
TextureManager::TextureHash hash,
- bool orientationCorrection )
+ bool orientationCorrection,
+ bool preMultiplyOnLoad )
: url( url ),
desiredSize( desiredSize ),
useSize( desiredSize ),
loadSynchronously( loadSynchronously ),
useAtlas( useAtlas ),
cropToMask( cropToMask ),
- orientationCorrection( true )
+ orientationCorrection( true ),
+ preMultiplyOnLoad( preMultiplyOnLoad ),
+ preMultiplied( false )
{
}
///< 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:
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.
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const bool useAtlas,
- TextureId maskTextureId );
+ TextureId maskTextureId,
+ MultiplyOnLoad preMultiplyOnLoad);
private:
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
-
};
* @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.
namespace Internal
{
-VisualFactoryCache::VisualFactoryCache()
-: mSvgRasterizeThread( NULL )
+VisualFactoryCache::VisualFactoryCache( bool preMultiplyOnLoad )
+: mSvgRasterizeThread( NULL ),
+ mPreMultiplyOnLoad( preMultiplyOnLoad )
{
}
return ResourceImage::New( BROKEN_VISUAL_IMAGE_URL );
}
+void VisualFactoryCache::SetPreMultiplyOnLoad( bool preMultiply )
+{
+ mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactoryCache::GetPreMultiplyOnLoad()
+{
+ return mPreMultiplyOnLoad;
+}
+
} // namespace Internal
} // namespace Toolkit
/**
* Caches shaders and geometries. Owned by VisualFactory.
*/
-class VisualFactoryCache : public RefObject
+class VisualFactoryCache
{
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.
*/
static Image GetBrokenVisualImage();
+ /**
+ * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+ */
+ void SetPreMultiplyOnLoad( bool preMultiply );
+
+ /**
+ * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+ */
+ bool GetPreMultiplyOnLoad();
+
public:
/**
* Get the image atlas manager.
protected:
/**
- * A reference counted object may only be deleted by calling Unreference()
- */
- virtual ~VisualFactoryCache();
-
- /**
* Undefined copy constructor.
*/
VisualFactoryCache(const VisualFactoryCache&);
TextureManager mTextureManager;
NPatchLoader mNPatchLoader;
SvgRasterizeThread* mSvgRasterizeThread;
+ bool mPreMultiplyOnLoad;
};
} // namespace Internal
} // namespace
VisualFactory::VisualFactory( bool debugEnabled )
-:mDebugEnabled( debugEnabled )
+: mDebugEnabled( debugEnabled ),
+ mPreMultiplyOnLoad( true )
{
}
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 );
{
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;
}
{
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;
}
}
Property::Array* array = imageURLValue->GetArray();
if( array )
{
- visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap );
+ visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap );
}
}
}
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;
}
std::string imageUrl;
if( imageURLValue && imageURLValue->Get( imageUrl ) )
{
- visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+ visualPtr = NPatchVisual::New( GetFactoryCache(), imageUrl, propertyMap );
}
break;
}
std::string imageUrl;
if( imageURLValue && imageURLValue->Get( imageUrl ) )
{
- visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+ visualPtr = SvgVisual::New( GetFactoryCache(), imageUrl, propertyMap );
}
break;
}
{
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 );
}
}
}
case Toolkit::DevelVisual::ANIMATED_GRADIENT:
{
- visualPtr = AnimatedGradientVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = AnimatedGradientVisual::New( GetFactoryCache(), propertyMap );
break;
}
}
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() );
Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
{
- if( !mFactoryCache )
- {
- mFactoryCache = new VisualFactoryCache();
- }
-
Visual::BasePtr visualPtr;
if( 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() );
Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimensions size )
{
- if( !mFactoryCache )
- {
- mFactoryCache = new VisualFactoryCache();
- }
-
Visual::BasePtr visualPtr;
if( !url.empty() )
{
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;
}
}
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
{
class VisualFactoryCache;
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
/**
* @copydoc Toolkit::VisualFactory
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();
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
};
/**