[dali_2.0.25] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / npatch-loader.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
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/npatch-loader.h>
20
21 // INTERNAL HEADERS
22 #include <dali-toolkit/internal/visuals/rendering-addon.h>
23
24 // EXTERNAL HEADERS
25 #include <dali/devel-api/common/hash.h>
26 #include <dali/integration-api/debug.h>
27
28 namespace Dali
29 {
30 namespace Toolkit
31 {
32 namespace Internal
33 {
34 namespace
35 {
36 constexpr auto INVALID_CACHE_INDEX = int32_t{-1}; ///< Invalid Cache index
37 constexpr auto UNINITIALIZED_ID    = int32_t{0};  ///< uninitialised id, use to initialize ids
38
39 } // Anonymous namespace
40
41 NPatchLoader::NPatchLoader()
42 : mCurrentNPatchDataId(0)
43 {
44 }
45
46 NPatchLoader::~NPatchLoader()
47 {
48 }
49
50 NPatchData::NPatchDataId NPatchLoader::GenerateUniqueNPatchDataId()
51 {
52   return mCurrentNPatchDataId++;
53 }
54
55 std::size_t NPatchLoader::Load(TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect<int>& border, bool& preMultiplyOnLoad, bool synchronousLoading)
56 {
57   std::size_t                                 hash  = CalculateHash(url);
58   OwnerContainer<NPatchData*>::SizeType       index = UNINITIALIZED_ID;
59   const OwnerContainer<NPatchData*>::SizeType count = mCache.Count();
60
61   for(; index < count; ++index)
62   {
63     if(mCache[index]->GetHash() == hash)
64     {
65       // hash match, check url as well in case of hash collision
66       if(mCache[index]->GetUrl() == url)
67       {
68         // Use cached data
69         if(mCache[index]->GetBorder() == border)
70         {
71           if(mCache[index]->GetLoadingState() == NPatchData::LoadingState::LOADING)
72           {
73             mCache[index]->AddObserver(textureObserver);
74           }
75           return mCache[index]->GetId(); // valid indices are from 1 onwards
76         }
77         else
78         {
79           if(mCache[index]->GetLoadingState() == NPatchData::LoadingState::LOAD_COMPLETE)
80           {
81             // Same url but border is different - use the existing texture
82             NPatchData* newData = new NPatchData();
83             newData->SetId(GenerateUniqueNPatchDataId());
84             newData->SetHash(hash);
85             newData->SetUrl(url);
86             newData->SetCroppedWidth(mCache[index]->GetCroppedWidth());
87             newData->SetCroppedHeight(mCache[index]->GetCroppedHeight());
88
89             newData->SetTextures(mCache[index]->GetTextures());
90
91             NPatchUtility::StretchRanges stretchRangesX;
92             stretchRangesX.PushBack(Uint16Pair(border.left, ((newData->GetCroppedWidth() >= static_cast<unsigned int>(border.right)) ? newData->GetCroppedHeight() - border.right : 0)));
93
94             NPatchUtility::StretchRanges stretchRangesY;
95             stretchRangesY.PushBack(Uint16Pair(border.top, ((newData->GetCroppedWidth() >= static_cast<unsigned int>(border.bottom)) ? newData->GetCroppedHeight() - border.bottom : 0)));
96
97             newData->SetStretchPixelsX(stretchRangesX);
98             newData->SetStretchPixelsY(stretchRangesY);
99             newData->SetBorder(border);
100
101             newData->SetPreMultiplyOnLoad(mCache[index]->IsPreMultiplied());
102
103             newData->SetLoadingState(NPatchData::LoadingState::LOAD_COMPLETE);
104             newData->AddObserver(textureObserver);
105
106             mCache.PushBack(newData);
107
108             return newData->GetId(); // valid ids start from 1u
109           }
110         }
111       }
112     }
113   }
114
115   // If this is new image loading, make new cache data
116   NPatchData* data;
117   data = new NPatchData();
118   data->SetId(GenerateUniqueNPatchDataId());
119   data->SetHash(hash);
120   data->SetUrl(url);
121   data->SetBorder(border);
122   data->SetPreMultiplyOnLoad(preMultiplyOnLoad);
123   data->AddObserver(textureObserver);
124   mCache.PushBack(data);
125
126   auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
127                                                 : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
128
129   Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer(url, Dali::ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, synchronousLoading, data, true, preMultiplyOnLoading);
130
131   if(pixelBuffer)
132   {
133     preMultiplyOnLoad = (preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) ? true : false;
134     data->SetLoadedNPatchData(pixelBuffer, preMultiplyOnLoad);
135   }
136
137   return data->GetId();
138 }
139
140 int32_t NPatchLoader::GetCacheIndexFromId(const NPatchData::NPatchDataId id)
141 {
142   const unsigned int size = mCache.Count();
143
144   for(unsigned int i = 0; i < size; ++i)
145   {
146     if(mCache[i]->GetId() == id)
147     {
148       return i;
149     }
150   }
151
152   return INVALID_CACHE_INDEX;
153 }
154
155 bool NPatchLoader::GetNPatchData(const NPatchData::NPatchDataId id, const NPatchData*& data)
156 {
157   int32_t cacheIndex = GetCacheIndexFromId(id);
158   if(cacheIndex != INVALID_CACHE_INDEX)
159   {
160     data = mCache[cacheIndex];
161     return true;
162   }
163   data = nullptr;
164   return false;
165 }
166
167 void NPatchLoader::Remove(std::size_t id, TextureUploadObserver* textureObserver)
168 {
169   int32_t cacheIndex = GetCacheIndexFromId(id);
170   if(cacheIndex == INVALID_CACHE_INDEX)
171   {
172     return;
173   }
174
175   NPatchData* data;
176   data = mCache[cacheIndex];
177
178   data->RemoveObserver(textureObserver);
179
180   if(data->GetObserverCount() == 0)
181   {
182     mCache.Erase(mCache.Begin() + cacheIndex);
183   }
184 }
185
186 } // namespace Internal
187
188 } // namespace Toolkit
189
190 } // namespace Dali