Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / npatch-loader.cpp
1  /*
2  * Copyright (c) 2016 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 HEADER
22 #include <dali/devel-api/common/hash.h>
23 #include <dali/devel-api/images/texture-set-image.h>
24 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 NPatchLoader::NPatchLoader()
36 {
37 }
38
39 NPatchLoader::~NPatchLoader()
40 {
41 }
42
43 std::size_t NPatchLoader::Load( const std::string& url, const Rect< int >& border )
44 {
45   std::size_t hash = CalculateHash( url );
46   OwnerContainer< Data* >::SizeType index = UNINITIALIZED_ID;
47   const OwnerContainer< Data* >::SizeType count = mCache.Count();
48   int cachedIndex = -1;
49
50   for( ; index < count; ++index )
51   {
52     if( mCache[ index ]->hash == hash )
53     {
54       // hash match, check url as well in case of hash collision
55       if( mCache[ index ]->url == url )
56       {
57         // Use cached data
58         if( mCache[ index ]->border == border )
59         {
60           return index+1u; // valid indices are from 1 onwards
61         }
62         else
63         {
64           cachedIndex = index;
65         }
66       }
67     }
68   }
69
70   if( cachedIndex != -1 )
71   {
72     // Same url but border is different - use the existing texture
73     Data* data = new Data();
74     data->hash = hash;
75     data->url = url;
76     data->croppedWidth = mCache[ cachedIndex ]->croppedWidth;
77     data->croppedHeight = mCache[ cachedIndex ]->croppedHeight;
78
79     data->textureSet = mCache[ cachedIndex ]->textureSet;
80
81     NinePatchImage::StretchRanges stretchRangesX;
82     stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) );
83
84     NinePatchImage::StretchRanges stretchRangesY;
85     stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) );
86
87     data->stretchPixelsX = stretchRangesX;
88     data->stretchPixelsY = stretchRangesY;
89     data->border = border;
90
91     mCache.PushBack( data );
92
93     return mCache.Count(); // valid ids start from 1u
94   }
95
96   // got to the end so no match, decode N patch and append new item to cache
97   if( border == Rect< int >( 0, 0, 0, 0 ) )
98   {
99     NinePatchImage ninePatch = NinePatchImage::New( url );
100     if( ninePatch )
101     {
102       BufferImage croppedImage = ninePatch.CreateCroppedBufferImage();
103       if( croppedImage )
104       {
105         Data* data = new Data();
106         data->hash = hash;
107         data->url = url;
108         data->textureSet = TextureSet::New();
109         TextureSetImage( data->textureSet, 0u, croppedImage );
110         data->croppedWidth = croppedImage.GetWidth();
111         data->croppedHeight = croppedImage.GetHeight();
112         data->stretchPixelsX = ninePatch.GetStretchPixelsX();
113         data->stretchPixelsY = ninePatch.GetStretchPixelsY();
114         data->border = Rect< int >( 0, 0, 0, 0 );
115         mCache.PushBack( data );
116
117         return mCache.Count(); // valid ids start from 1u
118       }
119     }
120   }
121   else
122   {
123     // Load image from file
124     PixelData pixels = SyncImageLoader::Load( url );
125     if( pixels )
126     {
127       Data* data = new Data();
128       data->hash = hash;
129       data->url = url;
130       data->croppedWidth = pixels.GetWidth();
131       data->croppedHeight = pixels.GetHeight();
132
133       Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
134       texture.Upload( pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight() );
135
136       data->textureSet = TextureSet::New();
137       data->textureSet.SetTexture( 0u, texture );
138
139       NinePatchImage::StretchRanges stretchRangesX;
140       stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) );
141
142       NinePatchImage::StretchRanges stretchRangesY;
143       stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) );
144
145       data->stretchPixelsX = stretchRangesX;
146       data->stretchPixelsY = stretchRangesY;
147       data->border = border;
148
149       mCache.PushBack( data );
150
151       return mCache.Count(); // valid ids start from 1u
152     }
153   }
154
155   return 0u;
156 }
157
158 bool NPatchLoader::GetNPatchData( std::size_t id, const Data*& data )
159 {
160   if( ( id > UNINITIALIZED_ID )&&( id <= mCache.Count() ) )
161   {
162     data = mCache[ id - 1u ]; // id's start from 1u
163     return true;
164   }
165   data = NULL;
166   return false;
167 }
168
169 } // namespace Internal
170
171 } // namespace Toolkit
172
173 } // namespace Dali