[dali_1.9.18] Merge branch 'devel/master'
[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 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/hash.h>
23 #include <dali/integration-api/debug.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 namespace Internal
32 {
33
34 namespace NPatchBuffer
35 {
36
37 void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuffer )
38 {
39   if( data->border == Rect< int >( 0, 0, 0, 0 ) )
40   {
41     NPatchUtility::ParseBorders( pixelBuffer, data->stretchPixelsX, data->stretchPixelsY );
42
43     // Crop the image
44     pixelBuffer.Crop( 1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2 );
45   }
46   else
47   {
48     data->stretchPixelsX.PushBack( Uint16Pair( data->border.left, ( (pixelBuffer.GetWidth() >= static_cast< unsigned int >( data->border.right )) ? pixelBuffer.GetWidth() - data->border.right : 0 ) ) );
49     data->stretchPixelsY.PushBack( Uint16Pair( data->border.top, ( (pixelBuffer.GetHeight() >= static_cast< unsigned int >( data->border.bottom )) ? pixelBuffer.GetHeight() - data->border.bottom : 0 ) ) );
50   }
51
52   data->croppedWidth = pixelBuffer.GetWidth();
53   data->croppedHeight = pixelBuffer.GetHeight();
54
55   PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer
56
57   Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
58   texture.Upload( pixels );
59
60   data->textureSet = TextureSet::New();
61   data->textureSet.SetTexture( 0u, texture );
62
63   data->loadCompleted = true;
64 }
65
66 } // namespace NPatchBuffer
67
68 NPatchLoader::NPatchLoader()
69 {
70 }
71
72 NPatchLoader::~NPatchLoader()
73 {
74 }
75
76 std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading )
77 {
78   std::size_t hash = CalculateHash( url );
79   OwnerContainer< Data* >::SizeType index = UNINITIALIZED_ID;
80   const OwnerContainer< Data* >::SizeType count = mCache.Count();
81   int cachedIndex = -1;
82   Data* data;
83
84   for( ; index < count; ++index )
85   {
86     if( mCache[ index ]->hash == hash )
87     {
88       // hash match, check url as well in case of hash collision
89       if( mCache[ index ]->url == url )
90       {
91         // Use cached data
92         if( mCache[ index ]->border == border )
93         {
94           if( mCache[ index ]->loadCompleted )
95           {
96             return index + 1u; // valid indices are from 1 onwards
97           }
98           data = mCache[ index ];
99           cachedIndex = index + 1u; // valid indices are from 1 onwards
100           break;
101         }
102         else
103         {
104           if( mCache[ index ]->loadCompleted )
105           {
106             // Same url but border is different - use the existing texture
107             Data* data = new Data();
108             data->hash = hash;
109             data->url = url;
110             data->croppedWidth = mCache[ index ]->croppedWidth;
111             data->croppedHeight = mCache[ index ]->croppedHeight;
112
113             data->textureSet = mCache[ index ]->textureSet;
114
115             NPatchUtility::StretchRanges stretchRangesX;
116             stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) );
117
118             NPatchUtility::StretchRanges stretchRangesY;
119             stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) );
120
121             data->stretchPixelsX = stretchRangesX;
122             data->stretchPixelsY = stretchRangesY;
123             data->border = border;
124
125             data->loadCompleted = mCache[ index ]->loadCompleted;
126
127             mCache.PushBack( data );
128
129             return mCache.Count(); // valid ids start from 1u
130           }
131         }
132       }
133     }
134   }
135
136   if( cachedIndex == -1 )
137   {
138     data = new Data();
139     data->loadCompleted = false;
140     data->hash = hash;
141     data->url = url;
142     data->border = border;
143
144     mCache.PushBack( data );
145
146     cachedIndex = mCache.Count();
147   }
148
149   auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
150                                                 : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
151   Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( url, Dali::ImageDimensions(), FittingMode::DEFAULT,
152                                                                    SamplingMode::BOX_THEN_LINEAR, synchronousLoading,
153                                                                    textureObserver, true, preMultiplyOnLoading );
154
155   if( pixelBuffer )
156   {
157     NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer );
158     preMultiplyOnLoad = ( preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) ? true : false;
159   }
160
161   return cachedIndex;
162 }
163
164 void NPatchLoader::SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer )
165 {
166   Data* data;
167   data = mCache[ id - 1u ];
168
169   if( !data->loadCompleted )
170   {
171     NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer );
172   }
173 }
174
175 bool NPatchLoader::GetNPatchData( std::size_t id, const Data*& data )
176 {
177   if( ( id > UNINITIALIZED_ID )&&( id <= mCache.Count() ) )
178   {
179     data = mCache[ id - 1u ]; // id's start from 1u
180     return true;
181   }
182   data = NULL;
183   return false;
184 }
185
186 } // namespace Internal
187
188 } // namespace Toolkit
189
190 } // namespace Dali