Prevent copy calls from repeat events of ctrl + c
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / npatch-data.cpp
1 /*
2  * Copyright (c) 2023 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
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/npatch-data.h>
20
21 // INTERNAL HEADERS
22 #include <dali-toolkit/internal/visuals/rendering-addon.h>
23
24 // EXTERNAL HEADERS
25 #include <dali/integration-api/debug.h>
26
27 namespace Dali
28 {
29 namespace Toolkit
30 {
31 namespace Internal
32 {
33 NPatchData::NPatchData()
34 : mId(INVALID_NPATCH_DATA_ID),
35   mUrl(),
36   mTextureSet(),
37   mHash(0),
38   mCroppedWidth(0),
39   mCroppedHeight(0),
40   mBorder(0, 0, 0, 0),
41   mLoadingState(LoadingState::NOT_STARTED),
42   mRenderingMap{nullptr},
43   mPreMultiplyOnLoad(false),
44   mObserverNotifying(false)
45 {
46 }
47
48 NPatchData::~NPatchData()
49 {
50   // If there is an opacity map, it has to be destroyed using addon call
51   if(mRenderingMap)
52   {
53     RenderingAddOn::Get().DestroyNPatch(mRenderingMap);
54   }
55   mObserverList.Clear();
56   mQueuedObservers.Clear();
57 }
58
59 void NPatchData::SetId(const NPatchDataId id)
60 {
61   mId = id;
62 }
63
64 NPatchData::NPatchDataId NPatchData::GetId() const
65 {
66   return mId;
67 }
68
69 void NPatchData::AddObserver(TextureUploadObserver* textureObserver)
70 {
71   if(mObserverNotifying)
72   {
73     // Do not add it into observer list during observer notifying.
74     mQueuedObservers.PushBack(textureObserver);
75   }
76   else
77   {
78     mObserverList.PushBack(textureObserver);
79   }
80   textureObserver->DestructionSignal().Connect(this, &NPatchData::ObserverDestroyed);
81 }
82
83 void NPatchData::RemoveObserver(TextureUploadObserver* textureObserver)
84 {
85   for(uint32_t index = 0; index < mObserverList.Count(); ++index)
86   {
87     if(textureObserver == mObserverList[index])
88     {
89       textureObserver->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
90       mObserverList.Erase(mObserverList.begin() + index);
91       break;
92     }
93   }
94 }
95
96 uint32_t NPatchData::GetObserverCount() const
97 {
98   return mObserverList.Count();
99 }
100
101 void NPatchData::SetUrl(const VisualUrl& url)
102 {
103   mUrl = url;
104 }
105
106 VisualUrl NPatchData::GetUrl() const
107 {
108   return mUrl;
109 }
110
111 void NPatchData::SetTextures(const TextureSet textureSet)
112 {
113   mTextureSet = textureSet;
114 }
115
116 TextureSet NPatchData::GetTextures() const
117 {
118   return mTextureSet;
119 }
120
121 void NPatchData::SetStretchPixelsX(const NPatchUtility::StretchRanges stretchPixelsX)
122 {
123   mStretchPixelsX = stretchPixelsX;
124 }
125
126 void NPatchData::SetStretchPixelsY(const NPatchUtility::StretchRanges stretchPixelsY)
127 {
128   mStretchPixelsY = stretchPixelsY;
129 }
130
131 NPatchUtility::StretchRanges NPatchData::GetStretchPixelsX() const
132 {
133   return mStretchPixelsX;
134 }
135
136 NPatchUtility::StretchRanges NPatchData::GetStretchPixelsY() const
137 {
138   return mStretchPixelsY;
139 }
140
141 void NPatchData::SetHash(std::size_t hash)
142 {
143   mHash = hash;
144 }
145
146 std::size_t NPatchData::GetHash() const
147 {
148   return mHash;
149 }
150
151 void NPatchData::SetCroppedWidth(uint32_t croppedWidth)
152 {
153   mCroppedWidth = croppedWidth;
154 }
155
156 void NPatchData::SetCroppedHeight(uint32_t croppedHeight)
157 {
158   mCroppedHeight = croppedHeight;
159 }
160
161 uint32_t NPatchData::GetCroppedWidth() const
162 {
163   return mCroppedWidth;
164 }
165
166 uint32_t NPatchData::GetCroppedHeight() const
167 {
168   return mCroppedHeight;
169 }
170
171 void NPatchData::SetBorder(const Rect<int> border)
172 {
173   mBorder = border;
174 }
175
176 Rect<int> NPatchData::GetBorder() const
177 {
178   return mBorder;
179 }
180
181 void NPatchData::SetPreMultiplyOnLoad(bool preMultiplyOnLoad)
182 {
183   mPreMultiplyOnLoad = preMultiplyOnLoad;
184 }
185
186 bool NPatchData::IsPreMultiplied() const
187 {
188   return mPreMultiplyOnLoad;
189 }
190
191 void NPatchData::SetLoadingState(const LoadingState loadingState)
192 {
193   mLoadingState = loadingState;
194 }
195
196 NPatchData::LoadingState NPatchData::GetLoadingState() const
197 {
198   return mLoadingState;
199 }
200
201 void* NPatchData::GetRenderingMap() const
202 {
203   return mRenderingMap;
204 }
205
206 void NPatchData::SetLoadedNPatchData(Devel::PixelBuffer& pixelBuffer, bool preMultiplied)
207 {
208   if(mBorder == Rect<int>(0, 0, 0, 0))
209   {
210     NPatchUtility::ParseBorders(pixelBuffer, mStretchPixelsX, mStretchPixelsY);
211
212     // Crop the image
213     pixelBuffer.Crop(1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2);
214   }
215   else
216   {
217     mStretchPixelsX.PushBack(Uint16Pair(mBorder.left, ((pixelBuffer.GetWidth() >= static_cast<unsigned int>(mBorder.right)) ? pixelBuffer.GetWidth() - mBorder.right : 0)));
218     mStretchPixelsY.PushBack(Uint16Pair(mBorder.top, ((pixelBuffer.GetHeight() >= static_cast<unsigned int>(mBorder.bottom)) ? pixelBuffer.GetHeight() - mBorder.bottom : 0)));
219   }
220
221   mCroppedWidth  = pixelBuffer.GetWidth();
222   mCroppedHeight = pixelBuffer.GetHeight();
223
224   // Create opacity map
225   mRenderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, this) : nullptr;
226
227   PixelData pixels = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
228
229   Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
230   texture.Upload(pixels);
231
232   mTextureSet = TextureSet::New();
233   mTextureSet.SetTexture(0u, texture);
234
235   mPreMultiplyOnLoad = preMultiplied;
236
237   mLoadingState = LoadingState::LOAD_COMPLETE;
238 }
239
240 void NPatchData::NotifyObserver(TextureUploadObserver* observer, const bool& loadSuccess)
241 {
242   observer->LoadComplete(
243     loadSuccess,
244     TextureUploadObserver::TextureInformation(
245       TextureUploadObserver::ReturnType::TEXTURE,
246       static_cast<TextureManager::TextureId>(mId), ///< Note : until end of NPatchLoader::Load, npatch-visual don't know the id of data.
247       mTextureSet,
248       mUrl.GetUrl(),
249       mPreMultiplyOnLoad));
250 }
251
252 void NPatchData::LoadComplete(bool loadSuccess, TextureInformation textureInformation)
253 {
254   if(loadSuccess)
255   {
256     if(mLoadingState != LoadingState::LOAD_COMPLETE)
257     {
258       // If mLoadingState is LOAD_FAILED, just re-set (It can be happened when sync loading is failed, but async loading is succeeded).
259       SetLoadedNPatchData(textureInformation.pixelBuffer, textureInformation.preMultiplied);
260     }
261   }
262   else
263   {
264     if(mLoadingState == LoadingState::LOADING)
265     {
266       mLoadingState = LoadingState::LOAD_FAILED;
267     }
268     // 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).
269     else if(mLoadingState == LoadingState::LOAD_COMPLETE)
270     {
271       loadSuccess = true;
272     }
273   }
274
275   mObserverNotifying = true;
276
277   // Reverse observer list that we can pop_back the observer.
278   std::reverse(mObserverList.Begin(), mObserverList.End());
279
280   while(mObserverList.Count() > 0u)
281   {
282     TextureUploadObserver* observer = *(mObserverList.End() - 1u);
283     mObserverList.Erase(mObserverList.End() - 1u);
284
285     observer->DestructionSignal().Disconnect(this, &NPatchData::ObserverDestroyed);
286
287     NotifyObserver(observer, loadSuccess);
288   }
289
290   mObserverNotifying = false;
291
292   // Swap observer list what we queued during notify observer.
293   // If mQueuedObserver is not empty, it mean mLoadingState was LOAD_FAILED, and we try to re-load for this data.
294   // (If mLoadingState was LOAD_COMPLETE, NotifyObserver will be called directly. @todo : Should we fix this logic, matched with texture manager?)
295   // So LoadComplete will be called.
296   mObserverList.Swap(mQueuedObservers);
297 }
298
299 void NPatchData::ObserverDestroyed(TextureUploadObserver* observer)
300 {
301   for(auto iter = mObserverList.Begin(); iter != mObserverList.End();)
302   {
303     if(observer == (*iter))
304     {
305       iter = mObserverList.Erase(iter);
306     }
307     else
308     {
309       ++iter;
310     }
311   }
312   if(mObserverNotifying)
313   {
314     for(auto iter = mQueuedObservers.Begin(); iter != mQueuedObservers.End();)
315     {
316       if(observer == (*iter))
317       {
318         iter = mQueuedObservers.Erase(iter);
319       }
320       else
321       {
322         ++iter;
323       }
324     }
325   }
326 }
327
328 } // namespace Internal
329
330 } // namespace Toolkit
331
332 } // namespace Dali