2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/visuals/npatch-data.h>
22 #include <dali-toolkit/internal/visuals/rendering-addon.h>
25 #include <dali/integration-api/debug.h>
33 NPatchData::NPatchData()
34 : mId(INVALID_NPATCH_DATA_ID),
41 mLoadingState(LoadingState::NOT_STARTED),
42 mRenderingMap{nullptr},
43 mPreMultiplyOnLoad(false),
44 mObserverNotifying(false)
48 NPatchData::~NPatchData()
50 // If there is an opacity map, it has to be destroyed using addon call
53 RenderingAddOn::Get().DestroyNPatch(mRenderingMap);
55 mObserverList.Clear();
56 mQueuedObservers.Clear();
59 void NPatchData::SetId(const NPatchDataId id)
64 NPatchData::NPatchDataId NPatchData::GetId() const
69 void NPatchData::AddObserver(TextureUploadObserver* textureObserver)
73 if(mObserverNotifying)
75 // Do not add it into observer list during observer notifying.
76 mQueuedObservers.PushBack(textureObserver);
80 mObserverList.PushBack(textureObserver);
82 textureObserver->DestructionSignal().Connect(this, &NPatchData::ObserverDestroyed);
86 void NPatchData::RemoveObserver(TextureUploadObserver* textureObserver)
90 for(uint32_t index = 0; index < mObserverList.Count(); ++index)
92 if(textureObserver == mObserverList[index])
94 textureObserver->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
95 mObserverList.Erase(mObserverList.begin() + index);
102 uint32_t NPatchData::GetObserverCount() const
104 return mObserverList.Count();
107 void NPatchData::SetUrl(const VisualUrl& url)
112 VisualUrl NPatchData::GetUrl() const
117 void NPatchData::SetTextures(const TextureSet textureSet)
119 mTextureSet = textureSet;
122 TextureSet NPatchData::GetTextures() const
127 void NPatchData::SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX)
129 mStretchPixelsX = stretchPixelsX;
132 void NPatchData::SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY)
134 mStretchPixelsY = stretchPixelsY;
137 NPatchUtility::StretchRanges NPatchData::GetStretchPixelsX() const
139 return mStretchPixelsX;
142 NPatchUtility::StretchRanges NPatchData::GetStretchPixelsY() const
144 return mStretchPixelsY;
147 void NPatchData::SetHash(std::size_t hash)
152 std::size_t NPatchData::GetHash() const
157 void NPatchData::SetCroppedWidth(uint32_t croppedWidth)
159 mCroppedWidth = croppedWidth;
162 void NPatchData::SetCroppedHeight(uint32_t croppedHeight)
164 mCroppedHeight = croppedHeight;
167 uint32_t NPatchData::GetCroppedWidth() const
169 return mCroppedWidth;
172 uint32_t NPatchData::GetCroppedHeight() const
174 return mCroppedHeight;
177 void NPatchData::SetBorder(const Rect<int> border)
182 Rect<int> NPatchData::GetBorder() const
187 void NPatchData::SetPreMultiplyOnLoad(bool preMultiplyOnLoad)
189 mPreMultiplyOnLoad = preMultiplyOnLoad;
192 bool NPatchData::IsPreMultiplied() const
194 return mPreMultiplyOnLoad;
197 void NPatchData::SetLoadingState(const LoadingState loadingState)
199 mLoadingState = loadingState;
202 NPatchData::LoadingState NPatchData::GetLoadingState() const
204 return mLoadingState;
207 void* NPatchData::GetRenderingMap() const
209 return mRenderingMap;
212 void NPatchData::SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied)
214 if(mBorder == Rect<int>(0, 0, 0, 0))
216 NPatchUtility::ParseBorders(pixelBuffer, mStretchPixelsX, mStretchPixelsY);
219 pixelBuffer.Crop(1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2);
223 mStretchPixelsX.PushBack(Uint16Pair(mBorder.left, ((pixelBuffer.GetWidth() >= static_cast<unsigned int>(mBorder.right)) ? pixelBuffer.GetWidth() - mBorder.right : 0)));
224 mStretchPixelsY.PushBack(Uint16Pair(mBorder.top, ((pixelBuffer.GetHeight() >= static_cast<unsigned int>(mBorder.bottom)) ? pixelBuffer.GetHeight() - mBorder.bottom : 0)));
227 mCroppedWidth = pixelBuffer.GetWidth();
228 mCroppedHeight = pixelBuffer.GetHeight();
230 // Create opacity map
231 mRenderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, this) : nullptr;
233 PixelData pixels = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
235 Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
236 texture.Upload(pixels);
238 mTextureSet = TextureSet::New();
239 mTextureSet.SetTexture(0u, texture);
241 mPreMultiplyOnLoad = preMultiplied;
243 mLoadingState = LoadingState::LOAD_COMPLETE;
246 void NPatchData::NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess)
248 observer->LoadComplete(
250 TextureUploadObserver::TextureInformation(
251 TextureUploadObserver::ReturnType::TEXTURE,
252 static_cast<TextureManager::TextureId>(mId), ///< Note : until end of NPatchLoader::Load, npatch-visual don't know the id of data.
255 mPreMultiplyOnLoad));
258 void NPatchData::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
260 NPatchDataPtr self = this; // Keep reference until this API finished
264 if(mLoadingState != LoadingState::LOAD_COMPLETE)
266 // If mLoadingState is LOAD_FAILED, just re-set (It can be happened when sync loading is failed, but async loading is succeeded).
267 SetLoadedNPatchData(textureInformation.pixelBuffer, textureInformation.preMultiplied);
272 if(mLoadingState == LoadingState::LOADING)
274 mLoadingState = LoadingState::LOAD_FAILED;
276 // If mLoadingState is already LOAD_COMPLETE, we can use uploaded texture (It can be happened when sync loading is succeeded, but async loading is failed).
277 else if(mLoadingState == LoadingState::LOAD_COMPLETE)
283 mObserverNotifying = true;
285 // Reverse observer list that we can pop_back the observer.
286 std::reverse(mObserverList.Begin(), mObserverList.End());
288 while(mObserverList.Count() > 0u)
290 TextureUploadObserver* observer = *(mObserverList.End() - 1u);
291 mObserverList.Erase(mObserverList.End() - 1u);
293 observer->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
295 NotifyObserver(observer, loadSuccess);
298 mObserverNotifying = false;
300 // Swap observer list what we queued during notify observer.
301 // If mQueuedObserver is not empty, it mean mLoadingState was LOAD_FAILED, and we try to re-load for this data.
302 // (If mLoadingState was LOAD_COMPLETE, NotifyObserver will be called directly. @todo : Should we fix this logic, matched with texture manager?)
303 // So LoadComplete will be called.
304 mObserverList.Swap(mQueuedObservers);
307 void NPatchData::ObserverDestroyed(TextureUploadObserver* observer)
309 for(auto iter = mObserverList.Begin(); iter != mObserverList.End();)
311 if(observer == (*iter))
313 iter = mObserverList.Erase(iter);
320 if(mObserverNotifying)
322 for(auto iter = mQueuedObservers.Begin(); iter != mQueuedObservers.End();)
324 if(observer == (*iter))
326 iter = mQueuedObservers.Erase(iter);
336 } // namespace Internal
338 } // namespace Toolkit