X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fanimated-image%2Fanimated-image-visual.cpp;h=9693cc834ffa57bc63ced05006c9403064e7cd3c;hb=HEAD;hp=382d52be83d775fec9eed00de954c6133db4773b;hpb=45ad62cd772319bc585a48c868b31892881374bb;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp index 382d52b..d94e0b5 100644 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,11 @@ */ // CLASS HEADER -#include "animated-image-visual.h" +#include // EXTERNAL INCLUDES #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +51,26 @@ namespace { const int CUSTOM_PROPERTY_COUNT(5); // ltr, wrap, pixel area, crop to mask, mask texture ratio +// fitting modes +DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT) +DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE) + +// sampling modes +DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER) + DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE) +DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE) + // stop behavior DALI_ENUM_TO_STRING_TABLE_BEGIN(STOP_BEHAVIOR) DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME) @@ -124,7 +146,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, " AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties) { - AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory)); + AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions())); visual->InitializeAnimatedImage(imageUrl); visual->SetProperties(properties); @@ -135,7 +157,7 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Property::Array& imageUrls, const Property::Map& properties) { - AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory)); + AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions())); visual->mImageUrls = new ImageCache::UrlList(); visual->mImageUrls->reserve(imageUrls.Count()); @@ -154,9 +176,9 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache return visual; } -AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl) +AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size) { - AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory)); + AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, size)); visual->InitializeAnimatedImage(imageUrl); visual->Initialize(); @@ -168,6 +190,22 @@ void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl) { mImageUrl = imageUrl; mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource()); + + // If we fail to load the animated image, we will try to load as a normal image. + if(!mAnimatedImageLoading) + { + mImageUrls = new ImageCache::UrlList(); + mImageUrls->reserve(SINGLE_IMAGE_COUNT); + + for(unsigned int i = 0; i < SINGLE_IMAGE_COUNT; ++i) + { + ImageCache::UrlStore urlStore; + urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID; + urlStore.mUrl = imageUrl; + mImageUrls->push_back(urlStore); + } + mFrameCount = SINGLE_IMAGE_COUNT; + } } void AnimatedImageVisual::CreateImageCache() @@ -178,7 +216,7 @@ void AnimatedImageVisual::CreateImageCache() if(mAnimatedImageLoading) { - mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, IsSynchronousLoadingRequired(), mFactoryCache.GetPreMultiplyOnLoad()); + mImageCache = new RollingAnimatedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, mWrapModeU, mWrapModeV, IsSynchronousLoadingRequired(), IsPreMultipliedAlphaEnabled()); } else if(mImageUrls) { @@ -189,22 +227,22 @@ void AnimatedImageVisual::CreateImageCache() uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE); if(cacheSize < numUrls) { - mImageCache = new RollingImageCache(textureManager, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay); + mImageCache = new RollingImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled()); } else { - mImageCache = new FixedImageCache(textureManager, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay); + mImageCache = new FixedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled()); } } - if(!mImageCache) + if(DALI_UNLIKELY(!mImageCache)) { DALI_LOG_ERROR("mImageCache is null\n"); } } -AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory) -: Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::ANIMATED_IMAGE), +AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize) +: Visual::Base(factoryCache, Visual::FittingMode::DONT_CARE, Toolkit::Visual::ANIMATED_IMAGE), mFrameDelayTimer(), mPlacementActor(), mImageVisualShaderFactory(shaderFactory), @@ -223,11 +261,14 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED), mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED), mMaskingData(), + mDesiredSize(desiredSize), mFrameCount(0), mImageSize(), mActionStatus(DevelAnimatedImageVisual::Action::PLAY), mWrapModeU(WrapMode::DEFAULT), mWrapModeV(WrapMode::DEFAULT), + mFittingMode(FittingMode::VISUAL_FITTING), + mSamplingMode(SamplingMode::BOX_THEN_LINEAR), mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME), mStartFirstFrame(false), mIsJumpTo(false) @@ -241,7 +282,10 @@ AnimatedImageVisual::~AnimatedImageVisual() // If this is animated image, clear cache. Else if this is single frame image, this is affected be release policy. if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER) { - mImageCache->ClearCache(); + if(DALI_LIKELY(mImageCache)) + { + mImageCache->ClearCache(); + } } delete mImageCache; delete mImageUrls; @@ -249,6 +293,34 @@ AnimatedImageVisual::~AnimatedImageVisual() void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize) { + if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0) + { + if(mImpl->mRenderer) + { + auto textureSet = mImpl->mRenderer.GetTextures(); + if(textureSet && textureSet.GetTextureCount()) + { + auto texture = textureSet.GetTexture(0); + if(texture) + { + Dali::Vector2 textureSize; + textureSize.x = texture.GetWidth(); + textureSize.y = texture.GetHeight(); + if(textureSize != Vector2::ZERO) + { + naturalSize = textureSize; + return; + } + } + } + } + + naturalSize.x = mDesiredSize.GetWidth(); + naturalSize.y = mDesiredSize.GetHeight(); + return; + } + + naturalSize = Vector2::ZERO; if(mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0) { if(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid() && @@ -264,7 +336,7 @@ void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize) } } - if(mImageUrl.IsValid()) + if(mImageUrl.IsValid() && mAnimatedImageLoading) { mImageSize = mAnimatedImageLoading.GetImageSize(); } @@ -311,7 +383,24 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast(mFrameDelay)); map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast(mLoopCount)); map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast(mImageCache->GetCurrentFrameIndex()) : -1); - map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() : mImageCache->GetTotalFrameCount()) : -1); + + // This returns -1 until the loading is finished. + auto frameCount = int32_t(mFrameCount); + if(mImageCache && frameCount == 0) + { + frameCount = mImageCache->GetTotalFrameCount(); + + if(frameCount <= int32_t(SINGLE_IMAGE_COUNT) && mAnimatedImageLoading && mAnimatedImageLoading.HasLoadingSucceeded()) + { + frameCount = int32_t(mAnimatedImageLoading.GetImageCount()); + } + else + { + frameCount = -1; + } + } + + map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast(frameCount)); map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior); @@ -325,11 +414,18 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy); map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy); + map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode); + map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight()); } void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const { - // Do nothing + map.Clear(); + map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth()); + map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight()); } void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes) @@ -466,6 +562,22 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap) { DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second); } + else if(keyValue.first == IMAGE_FITTING_MODE) + { + DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second); + } + else if(keyValue.first == IMAGE_SAMPLING_MODE) + { + DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second); + } + else if(keyValue.first == IMAGE_DESIRED_WIDTH) + { + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second); + } + else if(keyValue.first == IMAGE_DESIRED_HEIGHT) + { + DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second); + } } } // Load image immediately if LOAD_POLICY requires it @@ -552,7 +664,7 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, if(value.Get(frameDelay)) { mFrameDelay = frameDelay; - if(mImageCache) + if(DALI_LIKELY(mImageCache)) { mImageCache->SetInterval(static_cast(mFrameDelay)); } @@ -654,6 +766,50 @@ void AnimatedImageVisual::DoSetProperty(Property::Index index, mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy); break; } + + case Toolkit::ImageVisual::Property::FITTING_MODE: + { + int fittingMode = 0; + Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode); + mFittingMode = Dali::FittingMode::Type(fittingMode); + break; + } + + case Toolkit::ImageVisual::Property::SAMPLING_MODE: + { + int samplingMode = 0; + Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode); + mSamplingMode = Dali::SamplingMode::Type(samplingMode); + break; + } + + case Toolkit::ImageVisual::Property::DESIRED_WIDTH: + { + float desiredWidth = 0.0f; + if(value.Get(desiredWidth)) + { + mDesiredSize.SetWidth(desiredWidth); + } + else + { + DALI_LOG_ERROR("AnimatedImageVisual: desiredWidth property has incorrect type\n"); + } + break; + } + + case Toolkit::ImageVisual::Property::DESIRED_HEIGHT: + { + float desiredHeight = 0.0f; + if(value.Get(desiredHeight)) + { + mDesiredSize.SetHeight(desiredHeight); + } + else + { + DALI_LOG_ERROR("AnimatedImageVisual: desiredHeight property has incorrect type\n"); + } + break; + } } } @@ -662,6 +818,15 @@ void AnimatedImageVisual::DoSetOnScene(Actor& actor) mStartFirstFrame = true; mPlacementActor = actor; PrepareTextureSet(); + + actor.InheritedVisibilityChangedSignal().Connect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged); + + Window window = DevelWindow::Get(actor); + if(window) + { + mPlacementWindow = window; + DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedImageVisual::OnWindowVisibilityChanged); + } } void AnimatedImageVisual::DoSetOffScene(Actor& actor) @@ -677,7 +842,10 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor) actor.RemoveRenderer(mImpl->mRenderer); if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED) { - mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + if(DALI_LIKELY(mImageCache)) + { + mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas + } mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING; TextureSet textureSet = TextureSet::New(); @@ -688,6 +856,15 @@ void AnimatedImageVisual::DoSetOffScene(Actor& actor) mStartFirstFrame = false; mCurrentFrameIndex = FIRST_FRAME_INDEX; mCurrentLoopIndex = FIRST_LOOP; + + actor.InheritedVisibilityChangedSignal().Disconnect(this, &AnimatedImageVisual::OnControlInheritedVisibilityChanged); + + Window window = mPlacementWindow.GetHandle(); + if(window) + { + DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedImageVisual::OnWindowVisibilityChanged); + mPlacementWindow.Reset(); + } } void AnimatedImageVisual::OnSetTransform() @@ -714,7 +891,7 @@ Shader AnimatedImageVisual::GenerateShader() const Shader shader; shader = mImageVisualShaderFactory.GetShader( mFactoryCache, - ImageVisualShaderFeature::FeatureBuilder() + ImageVisualShaderFeatureBuilder() .ApplyDefaultTextureWrapMode(defaultWrapMode) .EnableRoundedCorner(IsRoundedCornerRequired()) .EnableBorderline(IsBorderlineRequired()) @@ -798,10 +975,15 @@ void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t first void AnimatedImageVisual::PrepareTextureSet() { TextureSet textureSet; - if(mImageCache) + if(DALI_LIKELY(mImageCache)) { textureSet = mImageCache->FirstFrame(); } + else + { + // preMultiplied should be false because broken image don't premultiply alpha on load + FrameReady(TextureSet(), 0, false); + } // Check whether synchronous loading is true or false for the first frame. if(textureSet) @@ -839,8 +1021,10 @@ void AnimatedImageVisual::SetImageSize(TextureSet& textureSet) } } -void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval) +void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval, bool preMultiplied) { + EnablePreMultipliedAlpha(preMultiplied); + // When image visual requested to load new frame to mImageCache and it is failed. if(!mImageCache || !textureSet) { @@ -850,7 +1034,10 @@ void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval) if(mStartFirstFrame) { - mFrameCount = mImageCache->GetTotalFrameCount(); + if(DALI_LIKELY(mImageCache)) + { + mFrameCount = mImageCache->GetTotalFrameCount(); + } StartFirstFrame(textureSet, interval); } else @@ -872,7 +1059,7 @@ bool AnimatedImageVisual::DisplayNextFrame() TextureSet textureSet; bool continueTimer = false; - if(mImageCache) + if(DALI_LIKELY(mImageCache)) { uint32_t frameIndex = mImageCache->GetCurrentFrameIndex(); @@ -954,8 +1141,13 @@ TextureSet AnimatedImageVisual::SetLoadingFailed() { imageSize = actor.GetProperty(Actor::Property::SIZE).Get(); } - mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); - TextureSet textureSet = mImpl->mRenderer.GetTextures(); + + TextureSet textureSet; + if(DALI_LIKELY(mImpl->mRenderer)) + { + mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize); + textureSet = mImpl->mRenderer.GetTextures(); + } if(mFrameDelayTimer) { @@ -994,6 +1186,26 @@ void AnimatedImageVisual::CheckMaskTexture() } } +void AnimatedImageVisual::OnControlInheritedVisibilityChanged(Actor actor, bool visible) +{ + if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP) + { + mActionStatus = DevelAnimatedImageVisual::Action::STOP; + DisplayNextFrame(); + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlInheritedVisibilityChanged: invisibile. Pause animation [%p]\n", this); + } +} + +void AnimatedImageVisual::OnWindowVisibilityChanged(Window window, bool visible) +{ + if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP) + { + mActionStatus = DevelAnimatedImageVisual::Action::STOP; + DisplayNextFrame(); + DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnWindowVisibilityChanged: invisibile. Pause animation [%p]\n", this); + } +} + } // namespace Internal } // namespace Toolkit