[Tizen] Add DesiredWidth/Height and samplingMode in animated image visual
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-image / fixed-image-cache.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // CLASS HEADER
18 #include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
19
20 // INTERNAL HEADERS
21 #include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
22
23 // EXTERNAL HEADERS
24 #include <dali/integration-api/debug.h>
25
26 namespace Dali
27 {
28 namespace Toolkit
29 {
30 namespace Internal
31 {
32 namespace
33 {
34 static constexpr bool ENABLE_ORIENTATION_CORRECTION(true);
35
36 static constexpr uint32_t FIRST_FRAME_INDEX = 0u;
37 } // namespace
38
39 FixedImageCache::FixedImageCache(TextureManager&                     textureManager,
40                                  ImageDimensions                     size,
41                                  Dali::SamplingMode::Type            samplingMode,
42                                  UrlList&                            urlList,
43                                  TextureManager::MaskingDataPointer& maskingData,
44                                  ImageCache::FrameReadyObserver&     observer,
45                                  uint32_t                            batchSize,
46                                  uint32_t                            interval)
47 : ImageCache(textureManager, size, samplingMode, maskingData, observer, batchSize, interval),
48   mImageUrls(urlList),
49   mFront(FIRST_FRAME_INDEX)
50 {
51   mLoadStates.assign(mImageUrls.size(), TextureManager::LoadState::NOT_STARTED);
52   mReadyFlags.reserve(mImageUrls.size());
53 }
54
55 FixedImageCache::~FixedImageCache()
56 {
57   ClearCache();
58 }
59
60 TextureSet FixedImageCache::Frame(uint32_t frameIndex)
61 {
62   while(frameIndex > mFront || mReadyFlags.empty() ||
63         (frameIndex == FIRST_FRAME_INDEX && mFront != FIRST_FRAME_INDEX))
64   {
65     ++mFront;
66     if(mFront >= mImageUrls.size())
67     {
68       mFront = 0;
69     }
70     LoadBatch();
71   }
72
73   mFront = frameIndex;
74
75   TextureSet textureSet;
76   if(IsFrontReady())
77   {
78     textureSet = GetFrontTextureSet();
79   }
80
81   return textureSet;
82 }
83
84 TextureSet FixedImageCache::FirstFrame()
85 {
86   TextureSet textureSet = Frame(FIRST_FRAME_INDEX);
87
88   return textureSet;
89 }
90
91 uint32_t FixedImageCache::GetFrameInterval(uint32_t frameIndex) const
92 {
93   return mInterval;
94 }
95
96 int32_t FixedImageCache::GetCurrentFrameIndex() const
97 {
98   return static_cast<int32_t>(mFront);
99 }
100
101 int32_t FixedImageCache::GetTotalFrameCount() const
102 {
103   return mImageUrls.size();
104 }
105
106 TextureManager::LoadState FixedImageCache::GetLoadState() const
107 {
108   return mLoadStates[mFront];
109 }
110
111 bool FixedImageCache::IsFrontReady() const
112 {
113   return (mReadyFlags.size() > 0 && mReadyFlags[mFront] == true);
114 }
115
116 void FixedImageCache::LoadBatch()
117 {
118   // Try and load up to mBatchSize images, until the cache is filled.
119   // Once the cache is filled, no more images are loaded.
120   for(unsigned int i = 0; i < mBatchSize && mReadyFlags.size() < mImageUrls.size(); ++i)
121   {
122     uint32_t frameIndex = mReadyFlags.size();
123     std::string& url = mImageUrls[frameIndex].mUrl;
124
125     mReadyFlags.push_back(false);
126
127     // Note, if the image is already loaded, then UploadComplete will get called
128     // from within this method. This means it won't yet have a texture id, so we
129     // need to account for this inside the UploadComplete method using mRequestingLoad.
130     mRequestingLoad = true;
131
132     bool                               synchronousLoading = false;
133     bool                               atlasingStatus     = false;
134     bool                               loadingStatus      = false;
135     AtlasUploadObserver*               atlasObserver      = nullptr;
136     ImageAtlasManagerPtr               imageAtlasManager  = nullptr;
137     Vector4                            textureRect;
138     Dali::ImageDimensions              textureRectSize;
139     auto                               preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
140
141     TextureSet textureSet = mTextureManager.LoadTexture(
142       url,
143       mDesiredSize,
144       FittingMode::SCALE_TO_FILL,
145       mSamplingMode,
146       mMaskingData,
147       synchronousLoading,
148       mImageUrls[frameIndex].mTextureId,
149       textureRect,
150       textureRectSize,
151       atlasingStatus,
152       loadingStatus,
153       Dali::WrapMode::Type::DEFAULT,
154       Dali::WrapMode::Type::DEFAULT,
155       this,
156       atlasObserver,
157       imageAtlasManager,
158       ENABLE_ORIENTATION_CORRECTION,
159       TextureManager::ReloadPolicy::CACHED,
160       preMultiply);
161
162     // If textureSet is returned but loadingState is false than load state is LOAD_FINISHED. (Notification is not comming yet.)
163     // If textureSet is null and the request is synchronous, load state is LOAD_FAILED.
164     // If textureSet is null but the request is asynchronous, the frame is still loading so load state is LOADING.
165     mLoadStates[frameIndex] = TextureManager::LoadState::LOADING;
166     if(textureSet)
167     {
168       if(!loadingStatus)
169       {
170         SetImageFrameReady(mImageUrls[frameIndex].mTextureId, true);
171       }
172     }
173     else if(synchronousLoading)
174     {
175       // Synchronous loading is failed
176       mLoadStates[frameIndex] = TextureManager::LoadState::LOAD_FAILED;
177     }
178
179     mRequestingLoad = false;
180   }
181 }
182
183 void FixedImageCache::SetImageFrameReady(TextureManager::TextureId textureId, bool loadSuccess)
184 {
185   for(std::size_t i = 0; i < mImageUrls.size(); ++i)
186   {
187     if(mImageUrls[i].mTextureId == textureId)
188     {
189       if(loadSuccess)
190       {
191         mLoadStates[i] = TextureManager::LoadState::LOAD_FINISHED;
192       }
193       else
194       {
195         mLoadStates[i] = TextureManager::LoadState::LOAD_FAILED;
196       }
197       mReadyFlags[i] = true;
198       break;
199     }
200   }
201 }
202
203 TextureSet FixedImageCache::GetFrontTextureSet() const
204 {
205   return mTextureManager.GetTextureSet(mImageUrls[mFront].mTextureId);
206 }
207
208 void FixedImageCache::CheckFrontFrame(bool wasReady)
209 {
210   if(wasReady == false && IsFrontReady())
211   {
212     mObserver.FrameReady(GetFrontTextureSet(), mInterval);
213   }
214 }
215
216 void FixedImageCache::ClearCache()
217 {
218   if(mTextureManagerAlive)
219   {
220     for(std::size_t i = 0; i < mImageUrls.size(); ++i)
221     {
222       mTextureManager.Remove(mImageUrls[i].mTextureId, this);
223       mImageUrls[i].mTextureId = TextureManager::INVALID_TEXTURE_ID;
224
225       if(mMaskingData && mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID)
226       {
227         mTextureManager.Remove(mMaskingData->mAlphaMaskId, this);
228       }
229     }
230   }
231   mReadyFlags.clear();
232   mLoadStates.assign(mImageUrls.size(), TextureManager::LoadState::NOT_STARTED);
233   mMaskingData->mAlphaMaskId = TextureManager::INVALID_TEXTURE_ID;
234 }
235
236 void FixedImageCache::UploadComplete(
237   bool           loadSuccess,
238   int32_t        textureId,
239   TextureSet     textureSet,
240   bool           useAtlasing,
241   const Vector4& atlasRect,
242   bool           preMultiplied)
243 {
244   bool frontFrameReady = IsFrontReady();
245   SetImageFrameReady(textureId, loadSuccess);
246   if(!mRequestingLoad)
247   {
248     CheckFrontFrame(frontFrameReady);
249   }
250 }
251
252 } //namespace Internal
253 } //namespace Toolkit
254 } //namespace Dali