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