Stop unnecessary copying of property maps in ImageView::SetImage
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / image-view / image-view-impl.cpp
1 // Copyright (c) 2016 Samsung Electronics Co., Ltd.
2
3 // CLASS HEADER
4 #include "image-view-impl.h"
5
6 // EXTERNAL INCLUDES
7 #include <dali/public-api/images/resource-image.h>
8 #include <dali/public-api/object/type-registry.h>
9 #include <dali/public-api/object/type-registry-helper.h>
10 #include <dali/devel-api/scripting/scripting.h>
11
12 // INTERNAL INCLUDES
13 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
14 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
15 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
16 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
17 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
18 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
19
20 namespace Dali
21 {
22
23 namespace Toolkit
24 {
25
26 namespace Internal
27 {
28
29 namespace
30 {
31
32 BaseHandle Create()
33 {
34   return Toolkit::ImageView::New();
35 }
36
37 // Setup properties, signals and actions using the type-registry.
38 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ImageView, Toolkit::Control, Create );
39 DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "resourceUrl", STRING, RESOURCE_URL )
40 DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "image", MAP, IMAGE )
41 DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA )
42
43 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA )
44 DALI_TYPE_REGISTRATION_END()
45
46 } // anonymous namespace
47
48 using namespace Dali;
49
50 ImageView::ImageView()
51 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) )
52 {
53 }
54
55 ImageView::~ImageView()
56 {
57 }
58
59 Toolkit::ImageView ImageView::New()
60 {
61   ImageView* impl = new ImageView();
62
63   Toolkit::ImageView handle = Toolkit::ImageView( *impl );
64
65   // Second-phase init of the implementation
66   // This can only be done after the CustomActor connection has been made...
67   impl->Initialize();
68
69   return handle;
70 }
71
72 /////////////////////////////////////////////////////////////
73
74 void ImageView::SetImage( Image image )
75 {
76   if( ( mImage != image ) ||
77       ! mUrl.empty()      ||   // If we're changing from a URL type to an Image type
78       ! mPropertyMap.Empty() ) // If we're changing from a property map type to an Image type
79   {
80     mUrl.clear();
81     mPropertyMap.Clear();
82
83     mImage = image;
84
85     mVisual =  Toolkit::VisualFactory::Get().CreateVisual( image );
86     RegisterVisual( Toolkit::ImageView::Property::IMAGE, mVisual  );
87     mImageSize = image ? ImageDimensions( image.GetWidth(), image.GetHeight() ) : ImageDimensions( 0, 0 );
88
89     RelayoutRequest();
90   }
91 }
92
93 void ImageView::SetImage( const Property::Map& map )
94 {
95   mUrl.clear();
96   mImage.Reset();
97   mPropertyMap = map;
98
99   mVisual =  Toolkit::VisualFactory::Get().CreateVisual( mPropertyMap );
100   RegisterVisual( Toolkit::ImageView::Property::IMAGE, mVisual  );
101
102   Property::Value* widthValue = mPropertyMap.Find( "width" );
103   if( widthValue )
104   {
105     int width;
106     if( widthValue->Get( width ) )
107     {
108       mImageSize = ImageDimensions( width, mImageSize.GetHeight() );
109     }
110   }
111
112   Property::Value* heightValue = mPropertyMap.Find( "height" );
113   if( heightValue )
114   {
115     int height;
116     if( heightValue->Get( height ) )
117     {
118       mImageSize = ImageDimensions( mImageSize.GetWidth(), height );
119     }
120   }
121
122   RelayoutRequest();
123 }
124
125 void ImageView::SetImage( const std::string& url, ImageDimensions size )
126 {
127   if( ( mUrl != url ) ||
128         mImage        ||       // If we're changing from an Image type to a URL type
129       ! mPropertyMap.Empty() ) // If we're changing from a property map type to a URL type
130   {
131     mImage.Reset();
132     mPropertyMap.Clear();
133
134     mUrl = url;
135
136     if( size.GetWidth() != 0u && size.GetHeight() != 0u )
137     {
138       mImageSize = size;
139     }
140
141     mVisual =  Toolkit::VisualFactory::Get().CreateVisual( url, size );
142     RegisterVisual( Toolkit::ImageView::Property::IMAGE, mVisual );
143
144     RelayoutRequest();
145   }
146 }
147
148 Image ImageView::GetImage() const
149 {
150   return mImage;
151 }
152
153 void ImageView::EnablePreMultipliedAlpha( bool preMultipled )
154 {
155   if( mVisual )
156   {
157     Toolkit::GetImplementation( mVisual ).EnablePreMultipliedAlpha( preMultipled );
158   }
159 }
160
161 bool ImageView::IsPreMultipliedAlphaEnabled() const
162 {
163   if( mVisual )
164   {
165     return Toolkit::GetImplementation( mVisual ).IsPreMultipliedAlphaEnabled();
166   }
167   return false;
168 }
169
170 void ImageView::SetDepthIndex( int depthIndex )
171 {
172   if( mVisual )
173   {
174     mVisual.SetDepthIndex( depthIndex );
175   }
176 }
177
178 Vector3 ImageView::GetNaturalSize()
179 {
180   if( mVisual )
181   {
182     Vector2 rendererNaturalSize;
183     mVisual.GetNaturalSize( rendererNaturalSize );
184     return Vector3( rendererNaturalSize );
185   }
186
187   Vector3 size;
188   size.x = mImageSize.GetWidth();
189   size.y = mImageSize.GetHeight();
190
191   if( size.x > 0 && size.y > 0 )
192   {
193     size.z = std::min(size.x, size.y);
194     return size;
195   }
196   else
197   {
198     // if no image then use Control's natural size
199     return Control::GetNaturalSize();
200   }
201 }
202
203 float ImageView::GetHeightForWidth( float width )
204 {
205   if( mImageSize.GetWidth() > 0 && mImageSize.GetHeight() > 0 )
206   {
207     return GetHeightForWidthBase( width );
208   }
209   else
210   {
211     return Control::GetHeightForWidth( width );
212   }
213 }
214
215 float ImageView::GetWidthForHeight( float height )
216 {
217   if( mImageSize.GetWidth() > 0 && mImageSize.GetHeight() > 0 )
218   {
219     return GetWidthForHeightBase( height );
220   }
221   else
222   {
223     return Control::GetWidthForHeight( height );
224   }
225 }
226
227 void ImageView::OnRelayout( const Vector2& size, RelayoutContainer& container )
228 {
229   Control::OnRelayout( size, container );
230
231   if( mVisual )
232   {
233     // Pass in an empty map which uses default transform values meaning our visual fills the control
234     // Should provide a transform that handles aspect ratio according to image size
235     mVisual.SetTransformAndSize( Property::Map(), size );
236   }
237 }
238
239 ///////////////////////////////////////////////////////////
240 //
241 // Properties
242 //
243
244 void ImageView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
245 {
246   Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( Dali::BaseHandle( object ) );
247
248   if ( imageView )
249   {
250     ImageView& impl = GetImpl( imageView );
251     switch ( index )
252     {
253       case Toolkit::ImageView::Property::RESOURCE_URL:
254       {
255         std::string imageUrl;
256         if( value.Get( imageUrl ) )
257         {
258           impl.SetImage( imageUrl, ImageDimensions() );
259         }
260         break;
261       }
262
263       case Toolkit::ImageView::Property::IMAGE:
264       {
265         std::string imageUrl;
266         Property::Map* map;
267         if( value.Get( imageUrl ) )
268         {
269           impl.SetImage( imageUrl, ImageDimensions() );
270         }
271         // if its not a string then get a Property::Map from the property if possible.
272         else
273         {
274           map = value.GetMap();
275           if( map )
276           {
277             Property::Value* shaderValue = map->Find( Toolkit::DevelVisual::Property::SHADER, CUSTOM_SHADER );
278             // set image only if property map contains image information other than custom shader
279             if( map->Count() > 1u ||  !shaderValue )
280             {
281               impl.SetImage( *map );
282             }
283             // the property map contains only the custom shader
284             else if( ( impl.mVisual )&&( map->Count() == 1u )&&( shaderValue ) )
285             {
286               Property::Map* shaderMap = shaderValue->GetMap();
287               if( shaderMap )
288               {
289                 Internal::Visual::Base& visual = Toolkit::GetImplementation( impl.mVisual );
290                 visual.SetCustomShader( *shaderMap );
291                 if( imageView.OnStage() )
292                 {
293                   // force to create new core renderer to use the newly set shader
294                   visual.SetOffStage( imageView );
295                   visual.SetOnStage( imageView );
296                 }
297               }
298             }
299           }
300         }
301         break;
302       }
303
304       case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
305       {
306         bool isPre;
307         if( value.Get( isPre ) )
308         {
309           impl.EnablePreMultipliedAlpha( isPre );
310         }
311         break;
312       }
313     }
314   }
315 }
316
317 Property::Value ImageView::GetProperty( BaseObject* object, Property::Index propertyIndex )
318 {
319   Property::Value value;
320
321   Toolkit::ImageView imageview = Toolkit::ImageView::DownCast( Dali::BaseHandle( object ) );
322
323   if ( imageview )
324   {
325     ImageView& impl = GetImpl( imageview );
326     switch ( propertyIndex )
327     {
328       case Toolkit::ImageView::Property::RESOURCE_URL:
329       {
330         if ( !impl.mUrl.empty() )
331         {
332           value = impl.mUrl;
333         }
334         break;
335       }
336
337       case Toolkit::ImageView::Property::IMAGE:
338       {
339         if ( !impl.mUrl.empty() )
340         {
341           value = impl.mUrl;
342         }
343         else if( impl.mImage )
344         {
345           Property::Map map;
346           Scripting::CreatePropertyMap( impl.mImage, map );
347           value = map;
348         }
349         else if( !impl.mPropertyMap.Empty() )
350         {
351           value = impl.mPropertyMap;
352         }
353         break;
354       }
355
356       case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
357       {
358         value = impl.IsPreMultipliedAlphaEnabled();
359         break;
360       }
361     }
362   }
363
364   return value;
365 }
366
367 } // namespace Internal
368 } // namespace Toolkit
369 } // namespace Dali