Create Renderer when the Visual is created
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-base-impl.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 "visual-base-impl.h"
20
21 // EXTERNAL HEADER
22 #include <dali-toolkit/public-api/dali-toolkit-common.h>
23 #include <dali/devel-api/scripting/enum-helper.h>
24 #include <dali/devel-api/rendering/renderer-devel.h>
25 #include <dali/integration-api/debug.h>
26
27 //INTERNAL HEARDER
28 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
29 #include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
30 #include <dali-toolkit/public-api/visuals/visual-properties.h>
31 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
32 #include <dali-toolkit/internal/helpers/property-helper.h>
33 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
35
36 namespace
37 {
38 #if defined(DEBUG_ENABLED)
39 Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VISUAL_BASE" );
40 #endif
41
42 const char * const PRE_MULTIPLIED_ALPHA_PROPERTY( "preMultipliedAlpha" );
43
44 } // namespace
45
46 namespace Dali
47 {
48
49 namespace Toolkit
50 {
51
52 namespace Internal
53 {
54
55 namespace
56 {
57
58 DALI_ENUM_TO_STRING_TABLE_BEGIN( VISUAL_FITTING_MODE )
59 DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, FIT_KEEP_ASPECT_RATIO  )
60 DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, FILL  )
61 DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, OVER_FIT_KEEP_ASPECT_RATIO )
62 DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, CENTER )
63 DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, FIT_WIDTH )
64 DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, FIT_HEIGHT )
65 DALI_ENUM_TO_STRING_TABLE_END( VISUAL_FITTING_MODE )
66
67 } // namespace
68
69 Visual::Base::Base( VisualFactoryCache& factoryCache, FittingMode fittingMode, Toolkit::Visual::Type type )
70 : mImpl( new Impl( fittingMode, type ) ),
71   mFactoryCache( factoryCache )
72 {
73 }
74
75 Visual::Base::~Base()
76 {
77   delete mImpl;
78 }
79
80 void Visual::Base::Initialize()
81 {
82   // The Renderer should be created inside derived class here.
83   OnInitialize();
84
85   if(mImpl->mRenderer)
86   {
87     RegisterMixColor();
88
89     if(IsRoundedCornerRequired())
90     {
91       mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
92       mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
93
94       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
95     }
96   }
97 }
98
99 void Visual::Base::SetCustomShader( const Property::Map& shaderMap )
100 {
101   if( mImpl->mCustomShader )
102   {
103     mImpl->mCustomShader->SetPropertyMap( shaderMap );
104   }
105   else
106   {
107     mImpl->mCustomShader = new Impl::CustomShader( shaderMap );
108   }
109
110   // Let derived class know
111   UpdateShader();
112 }
113
114 void Visual::Base::SetProperties( const Property::Map& propertyMap )
115 {
116   for( size_t i = 0; i < propertyMap.Count(); ++i )
117   {
118     const KeyValuePair& pair = propertyMap.GetKeyValue( i );
119     const Property::Key& key = pair.first;
120     const Property::Value& value = pair.second;
121
122     Property::Key matchKey = key;
123     if( matchKey.type == Property::Key::STRING )
124     {
125       if( matchKey == CUSTOM_SHADER )
126       {
127         matchKey = Property::Key( Toolkit::Visual::Property::SHADER );
128       }
129       else if( matchKey == TRANSFORM )
130       {
131         matchKey = Property::Key( Toolkit::Visual::Property::TRANSFORM );
132       }
133       else if( matchKey == PREMULTIPLIED_ALPHA )
134       {
135         matchKey = Property::Key( Toolkit::Visual::Property::PREMULTIPLIED_ALPHA );
136       }
137       else if( matchKey == MIX_COLOR )
138       {
139         matchKey = Property::Key( Toolkit::Visual::Property::MIX_COLOR );
140       }
141       else if( matchKey == OPACITY )
142       {
143         matchKey = Property::Key( Toolkit::Visual::Property::OPACITY );
144       }
145       else if( matchKey == VISUAL_FITTING_MODE )
146       {
147         matchKey = Property::Key( Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE );
148       }
149       else if( matchKey == CORNER_RADIUS )
150       {
151         matchKey = Property::Key( Toolkit::DevelVisual::Property::CORNER_RADIUS );
152       }
153       else if( matchKey == CORNER_RADIUS_POLICY )
154       {
155         matchKey = Property::Key( Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY );
156       }
157     }
158
159     switch( matchKey.indexKey )
160     {
161       case Toolkit::Visual::Property::SHADER:
162       {
163         Property::Map shaderMap;
164         if( value.Get( shaderMap ) )
165         {
166           SetCustomShader( shaderMap );
167         }
168         break;
169       }
170
171       case Toolkit::Visual::Property::TRANSFORM:
172       {
173         Property::Map map;
174         if( value.Get( map ) )
175         {
176           mImpl->mTransform.SetPropertyMap( map );
177         }
178         break;
179       }
180
181       case Toolkit::Visual::Property::PREMULTIPLIED_ALPHA:
182       {
183         bool premultipliedAlpha = false;
184         if( value.Get( premultipliedAlpha ) )
185         {
186           EnablePreMultipliedAlpha( premultipliedAlpha );
187         }
188         break;
189       }
190
191       case Toolkit::Visual::Property::MIX_COLOR:
192       {
193         Vector4 mixColor;
194         if( value.Get( mixColor ) )
195         {
196           if( value.GetType() == Property::VECTOR4 )
197           {
198             SetMixColor( mixColor );
199           }
200           else
201           {
202             Vector3 mixColor3(mixColor);
203             SetMixColor( mixColor3 );
204           }
205         }
206         break;
207       }
208       case Toolkit::Visual::Property::OPACITY:
209       {
210         float opacity;
211         if( value.Get( opacity ) )
212         {
213           mImpl->mMixColor.a = opacity;
214           SetMixColor( mImpl->mMixColor );
215         }
216         break;
217       }
218       case Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE:
219       {
220         Scripting::GetEnumerationProperty< Visual::FittingMode >(
221           value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode );
222         break;
223       }
224       case Toolkit::DevelVisual::Property::CORNER_RADIUS:
225       {
226         float radius;
227         if( value.Get( radius ) )
228         {
229           mImpl->mCornerRadius = radius;
230         }
231         break;
232       }
233       case Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY:
234       {
235         int policy;
236         if( value.Get( policy ) )
237         {
238           switch( policy )
239           {
240             case Toolkit::Visual::Transform::Policy::RELATIVE:
241             case Toolkit::Visual::Transform::Policy::ABSOLUTE:
242             {
243               mImpl->mCornerRadiusPolicy = policy;
244               break;
245             }
246             default:
247             {
248               DALI_LOG_ERROR( "Unsupported policy: %d\n", policy );
249               break;
250             }
251           }
252         }
253         break;
254       }
255     }
256   }
257
258   DoSetProperties( propertyMap );
259 }
260
261 void Visual::Base::SetTransformAndSize( const Property::Map& transform, Size controlSize )
262 {
263   mImpl->mControlSize = controlSize;
264   mImpl->mTransform.UpdatePropertyMap( transform );
265
266 #if defined(DEBUG_ENABLED)
267   std::ostringstream oss;
268   oss << transform;
269   DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::SetTransformAndSize(%s) - [\e[1;32mtransform: %s  controlSize: (%3.1f, %3.1f)]\e[0m\n",
270                  GetName().c_str(), oss.str().c_str(), controlSize.x, controlSize.y );
271 #endif
272
273   OnSetTransform();
274 }
275
276 void Visual::Base::SetName( const std::string& name )
277 {
278   mImpl->mName = name;
279 }
280
281 const std::string& Visual::Base::GetName() const
282 {
283   return mImpl->mName;
284 }
285
286 float Visual::Base::GetHeightForWidth( float width )
287 {
288   float aspectCorrectedHeight = 0.f;
289   Vector2 naturalSize;
290   GetNaturalSize( naturalSize );
291   if( naturalSize.width )
292   {
293     aspectCorrectedHeight = naturalSize.height * width / naturalSize.width;
294   }
295   return aspectCorrectedHeight;
296 }
297
298 float Visual::Base::GetWidthForHeight( float height )
299 {
300   float aspectCorrectedWidth = 0.f;
301   Vector2 naturalSize;
302   GetNaturalSize( naturalSize );
303   if( naturalSize.height > 0.0f )
304   {
305     aspectCorrectedWidth = naturalSize.width * height / naturalSize.height;
306   }
307   return aspectCorrectedWidth;
308 }
309
310 void Visual::Base::GetNaturalSize( Vector2& naturalSize )
311 {
312   naturalSize = Vector2::ZERO;
313 }
314
315 void Visual::Base::DoAction( const Property::Index actionId, const Property::Value attributes )
316 {
317   OnDoAction( actionId, attributes );
318 }
319
320 void Visual::Base::SetDepthIndex( int index )
321 {
322   mImpl->mDepthIndex = index;
323   if( mImpl->mRenderer )
324   {
325     mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
326   }
327 }
328
329 int Visual::Base::GetDepthIndex() const
330 {
331   return mImpl->mDepthIndex;
332 }
333
334 void Visual::Base::SetOnScene( Actor& actor )
335 {
336   if( !IsOnScene() )
337   {
338     // To display the actor correctly, renderer should not be added to actor until all required resources are ready.
339     // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing.
340     DoSetOnScene( actor );
341
342     if(mImpl->mRenderer)
343     {
344       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
345       mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex);
346     }
347
348     mImpl->mFlags |= Impl::IS_ON_SCENE;
349   }
350 }
351
352 void Visual::Base::SetOffScene( Actor& actor )
353 {
354   if( IsOnScene() )
355   {
356     DoSetOffScene( actor );
357     mImpl->mFlags &= ~Impl::IS_ON_SCENE;
358   }
359 }
360
361 void Visual::Base::CreatePropertyMap( Property::Map& map ) const
362 {
363   if(mImpl->mRenderer)
364   {
365     // Update values from Renderer
366     mImpl->mMixColor   = mImpl->mRenderer.GetProperty<Vector3>(mImpl->mMixColorIndex);
367     mImpl->mMixColor.a = mImpl->mRenderer.GetProperty<float>(DevelRenderer::Property::OPACITY);
368     if(mImpl->mTransform.mOffsetIndex != Property::INVALID_INDEX)
369     {
370       mImpl->mTransform.mOffset = mImpl->mRenderer.GetProperty<Vector2>(mImpl->mTransform.mOffsetIndex);
371     }
372     if(mImpl->mTransform.mSizeIndex != Property::INVALID_INDEX)
373     {
374       mImpl->mTransform.mSize = mImpl->mRenderer.GetProperty<Vector2>(mImpl->mTransform.mSizeIndex);
375     }
376     if(mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
377     {
378       mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<float>(mImpl->mCornerRadiusIndex);
379     }
380   }
381
382   DoCreatePropertyMap(map);
383
384   if(mImpl->mCustomShader)
385   {
386     mImpl->mCustomShader->CreatePropertyMap(map);
387   }
388
389   Property::Map transform;
390   mImpl->mTransform.GetPropertyMap( transform );
391   map.Insert( Toolkit::Visual::Property::TRANSFORM, transform );
392
393   bool premultipliedAlpha( IsPreMultipliedAlphaEnabled() );
394   map.Insert( Toolkit::Visual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha );
395
396   // Note, Color and Primitive will also insert their own mix color into the map
397   // which is ok, because they have a different key value range.
398   map.Insert( Toolkit::Visual::Property::MIX_COLOR, mImpl->mMixColor ); // vec4
399   map.Insert( Toolkit::Visual::Property::OPACITY, mImpl->mMixColor.a );
400
401   auto fittingModeString = Scripting::GetLinearEnumerationName< FittingMode >(
402     mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT );
403   map.Insert( Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString );
404
405   map.Insert( Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius );
406   map.Insert( Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast< int >( mImpl->mCornerRadiusPolicy ) );
407 }
408
409 void Visual::Base::CreateInstancePropertyMap( Property::Map& map ) const
410 {
411   DoCreateInstancePropertyMap( map );
412
413   if( mImpl->mCustomShader )
414   {
415     mImpl->mCustomShader->CreatePropertyMap( map );
416   }
417 }
418
419
420 void Visual::Base::EnablePreMultipliedAlpha( bool preMultiplied )
421 {
422   if( preMultiplied )
423   {
424     mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
425   }
426   else
427   {
428     mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
429   }
430
431   if( mImpl->mRenderer )
432   {
433     mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultiplied);
434     mImpl->mRenderer.RegisterProperty( PRE_MULTIPLIED_ALPHA_PROPERTY, static_cast<float>( preMultiplied ) );
435   }
436 }
437
438 bool Visual::Base::IsPreMultipliedAlphaEnabled() const
439 {
440   return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA;
441 }
442
443 void Visual::Base::DoSetOffScene( Actor& actor )
444 {
445   actor.RemoveRenderer( mImpl->mRenderer );
446 }
447
448 bool Visual::Base::IsOnScene() const
449 {
450   return mImpl->mFlags & Impl::IS_ON_SCENE;
451 }
452
453 bool Visual::Base::IsRoundedCornerRequired() const
454 {
455   if(mImpl->mRenderer && mImpl->mCornerRadiusIndex != Property::INVALID_INDEX)
456   {
457     // Update values from Renderer
458     mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<float>(mImpl->mCornerRadiusIndex);
459   }
460   return !EqualsZero(mImpl->mCornerRadius) || mImpl->mNeedCornerRadius;
461 }
462
463 void Visual::Base::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
464 {
465   // May be overriden by derived class
466 }
467
468 void Visual::Base::RegisterMixColor()
469 {
470   // Only register if not already registered.
471   // (Color and Primitive visuals will register their own and save to this index)
472   if( mImpl->mMixColorIndex == Property::INVALID_INDEX )
473   {
474     mImpl->mMixColorIndex = mImpl->mRenderer.RegisterProperty(
475       Toolkit::Visual::Property::MIX_COLOR,
476       MIX_COLOR,
477       Vector3(mImpl->mMixColor) );
478   }
479
480   mImpl->mRenderer.SetProperty( DevelRenderer::Property::OPACITY, mImpl->mMixColor.a );
481
482   float preMultipliedAlpha = 0.0f;
483   if( IsPreMultipliedAlphaEnabled() )
484   {
485     preMultipliedAlpha = 1.0f;
486   }
487   mImpl->mRenderer.RegisterProperty( PRE_MULTIPLIED_ALPHA_PROPERTY, preMultipliedAlpha );
488 }
489
490 void Visual::Base::SetMixColor( const Vector4& color )
491 {
492   mImpl->mMixColor = color;
493
494   if( mImpl->mRenderer )
495   {
496     mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, Vector3(color) );
497     mImpl->mRenderer.SetProperty( DevelRenderer::Property::OPACITY, color.a );
498   }
499 }
500
501 void Visual::Base::SetMixColor( const Vector3& color )
502 {
503   mImpl->mMixColor.r = color.r;
504   mImpl->mMixColor.g = color.g;
505   mImpl->mMixColor.b = color.b;
506
507   if( mImpl->mRenderer )
508   {
509     mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, color );
510   }
511 }
512
513 void Visual::Base::AddEventObserver( Visual::EventObserver& observer)
514 {
515   mImpl->mEventObserver = &observer;
516 }
517
518 void Visual::Base::RemoveEventObserver( Visual::EventObserver& observer )
519 {
520   mImpl->mEventObserver = NULL;
521 }
522
523 void Visual::Base::ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus)
524 {
525   if( mImpl->mResourceStatus != resourceStatus )
526   {
527     mImpl->mResourceStatus = resourceStatus;
528
529     if( mImpl->mEventObserver )
530     {
531       // observer is currently a control impl
532       mImpl->mEventObserver->ResourceReady( *this );
533     }
534   }
535 }
536
537 bool Visual::Base::IsResourceReady() const
538 {
539   return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY );
540 }
541
542 bool Visual::Base::IsSynchronousLoadingRequired() const
543 {
544   return ( mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING );
545 }
546
547 Toolkit::Visual::Type Visual::Base::GetType() const
548 {
549   return mImpl->mType;
550 }
551
552 Toolkit::Visual::ResourceStatus Visual::Base::GetResourceStatus() const
553 {
554   return mImpl->mResourceStatus;
555 }
556
557 Visual::FittingMode Visual::Base::GetFittingMode() const
558 {
559   return mImpl->mFittingMode;
560 }
561
562 Visual::Base& Visual::Base::GetVisualObject()
563 {
564   return *this;
565 }
566
567 Renderer Visual::Base::GetRenderer()
568 {
569   return mImpl->mRenderer;
570 }
571
572 Property::Index Visual::Base::GetPropertyIndex( Property::Key key )
573 {
574   Property::Index index = mImpl->mRenderer.GetPropertyIndex( key );
575
576   if( index == Property::INVALID_INDEX )
577   {
578     // Is it a shader property?
579     Shader shader = mImpl->mRenderer.GetShader();
580     index = shader.GetPropertyIndex( key );
581     if( index != Property::INVALID_INDEX )
582     {
583       // Yes - we should register it in the Renderer so it can be set / animated
584       // independently, as shaders are shared across multiple renderers.
585       std::string keyName;
586       Property::Index keyIndex( Property::INVALID_KEY );
587       if( key.type == Property::Key::INDEX )
588       {
589         keyName = shader.GetPropertyName( index );
590         keyIndex = key.indexKey;
591       }
592       else
593       {
594         keyName = key.stringKey;
595         // Leave keyIndex as INVALID_KEY - it can still be registered against the string key.
596       }
597       Property::Value value = shader.GetProperty( index );
598       index = mImpl->mRenderer.RegisterProperty( keyIndex, keyName, value );
599     }
600   }
601   return index;
602 }
603
604 void Visual::Base::SetupTransition(
605   Dali::Animation& transition,
606   Internal::TransitionData::Animator& animator,
607   Property::Index index,
608   Property::Value& initialValue,
609   Property::Value& targetValue )
610 {
611   if( index != Property::INVALID_INDEX )
612   {
613     if( mImpl->mRenderer )
614     {
615       if( animator.animate == false )
616       {
617         mImpl->mRenderer.SetProperty( index, targetValue );
618       }
619       else
620       {
621         if( animator.initialValue.GetType() != Property::NONE )
622         {
623           mImpl->mRenderer.SetProperty( index, initialValue );
624         }
625
626         if( ! transition )
627         {
628           transition = Dali::Animation::New( 0.1f );
629         }
630
631         transition.AnimateTo( Property( mImpl->mRenderer, index ),
632                               targetValue,
633                               animator.alphaFunction,
634                               TimePeriod( animator.timePeriodDelay,
635                                           animator.timePeriodDuration ) );
636       }
637     }
638   }
639 }
640
641 void Visual::Base::AnimateProperty(
642   Dali::Animation& transition,
643   Internal::TransitionData::Animator& animator )
644 {
645 #if defined(DEBUG_ENABLED)
646   {
647     std::ostringstream oss;
648     oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
649     DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, oss.str().c_str() );
650   }
651 #endif
652
653   if(animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR ||
654      animator.propertyKey == MIX_COLOR ||
655      (mImpl->mType == Toolkit::Visual::COLOR &&
656       animator.propertyKey == ColorVisual::Property::MIX_COLOR) ||
657      (mImpl->mType == Toolkit::Visual::PRIMITIVE &&
658       animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR))
659   {
660     AnimateMixColorProperty( transition, animator );
661   }
662   else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY ||
663           animator.propertyKey == OPACITY )
664   {
665     AnimateOpacityProperty( transition, animator );
666   }
667   else if( mImpl->mRenderer )
668   {
669     AnimateRendererProperty( transition, animator );
670   }
671 }
672
673 void Visual::Base::AnimateOpacityProperty(
674   Dali::Animation& transition,
675   Internal::TransitionData::Animator& animator )
676 {
677   float targetOpacity;
678   if( animator.targetValue.Get( targetOpacity ) )
679   {
680     mImpl->mMixColor.a = targetOpacity;
681   }
682
683   SetupTransition( transition, animator, DevelRenderer::Property::OPACITY, animator.initialValue, animator.targetValue );
684 }
685
686 void Visual::Base::AnimateRendererProperty(
687   Dali::Animation& transition,
688   Internal::TransitionData::Animator& animator )
689 {
690   Property::Index index = GetPropertyIndex( animator.propertyKey );
691   if( index != Property::INVALID_INDEX )
692   {
693     if( animator.targetValue.GetType() != Property::NONE )
694     {
695       // Try writing target value into transform property map
696       // if it's not a valid key, then it won't alter mTransform
697       Property::Map map;
698       if( animator.propertyKey.type == Property::Key::INDEX )
699       {
700         map.Add( animator.propertyKey.indexKey, animator.targetValue );
701       }
702       else
703       {
704         map.Add( animator.propertyKey.stringKey, animator.targetValue );
705       }
706
707       mImpl->mTransform.UpdatePropertyMap( map );
708     }
709
710     SetupTransition( transition, animator, index, animator.initialValue, animator.targetValue );
711   }
712 }
713
714 void Visual::Base::AnimateMixColorProperty(
715   Dali::Animation& transition,
716   Internal::TransitionData::Animator& animator )
717 {
718   Property::Index index = mImpl->mMixColorIndex;
719   bool animateOpacity = false;
720
721   Property::Value initialOpacity;
722   Property::Value targetOpacity;
723   Property::Value initialMixColor;
724   Property::Value targetMixColor;
725
726   if( index != Property::INVALID_INDEX )
727   {
728     Vector4 initialColor;
729     if( animator.initialValue.Get(initialColor) )
730     {
731       if( animator.initialValue.GetType() == Property::VECTOR4 )
732       {
733         // if there is an initial color specifying alpha, test it
734         initialOpacity = initialColor.a;
735       }
736       initialMixColor = Vector3( initialColor );
737     }
738
739     // Set target value into data store
740     if( animator.targetValue.GetType() != Property::NONE )
741     {
742       Vector4 mixColor;
743       animator.targetValue.Get(mixColor);
744       if( animator.targetValue.GetType() == Property::VECTOR4 )
745       {
746         mImpl->mMixColor.a = mixColor.a;
747         targetOpacity = mixColor.a;
748         animateOpacity = true;
749       }
750
751       mImpl->mMixColor.r = mixColor.r;
752       mImpl->mMixColor.g = mixColor.g;
753       mImpl->mMixColor.b = mixColor.b;
754       targetMixColor = Vector3(mixColor);
755     }
756
757     SetupTransition( transition, animator, index, initialMixColor, targetMixColor );
758     if( animateOpacity )
759     {
760       SetupTransition( transition, animator, DevelRenderer::Property::OPACITY, initialOpacity, targetOpacity );
761     }
762   }
763 }
764
765 Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
766 {
767   if(!mImpl->mRenderer)
768   {
769     Handle handle;
770     return Dali::Property(handle, Property::INVALID_INDEX);
771   }
772
773   // Mix color or opacity cases
774   if(key.type == Property::Key::INDEX)
775   {
776     if(key.indexKey == Toolkit::Visual::Property::MIX_COLOR || (mImpl->mType == Toolkit::Visual::COLOR && key.indexKey == ColorVisual::Property::MIX_COLOR) || (mImpl->mType == Toolkit::Visual::PRIMITIVE && key.indexKey == PrimitiveVisual::Property::MIX_COLOR))
777     {
778       return Dali::Property(mImpl->mRenderer, mImpl->mMixColorIndex);
779     }
780     else if(key.indexKey == Toolkit::Visual::Property::OPACITY)
781     {
782       return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY);
783     }
784     else if(key.indexKey == Toolkit::Visual::Transform::Property::OFFSET)
785     {
786       return Dali::Property(mImpl->mRenderer, OFFSET);
787     }
788     else if(key.indexKey == Toolkit::Visual::Transform::Property::SIZE)
789     {
790       return Dali::Property(mImpl->mRenderer, SIZE);
791     }
792   }
793   else
794   {
795     if(key.stringKey == MIX_COLOR)
796     {
797       return Dali::Property(mImpl->mRenderer, mImpl->mMixColorIndex);
798     }
799     else if(key.stringKey == OPACITY)
800     {
801       return Dali::Property(mImpl->mRenderer, DevelRenderer::Property::OPACITY);
802     }
803     else if(key.stringKey == OFFSET)
804     {
805       return Dali::Property(mImpl->mRenderer, OFFSET);
806     }
807     else if(key.stringKey == SIZE)
808     {
809       return Dali::Property(mImpl->mRenderer, SIZE);
810     }
811   }
812
813   // Other cases
814   Property::Index index = GetPropertyIndex(key);
815   if(index == Property::INVALID_INDEX)
816   {
817     if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
818     {
819       // Register CORNER_RADIUS property
820       mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
821       mImpl->mRenderer.RegisterProperty(CORNER_RADIUS_POLICY, mImpl->mCornerRadiusPolicy);
822
823       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
824
825       index = mImpl->mCornerRadiusIndex;
826       mImpl->mNeedCornerRadius = true;
827
828       // Change shader
829       UpdateShader();
830     }
831     else
832     {
833       // We can't find the property in the base class.
834       // Request to child class
835       return OnGetPropertyObject(key);
836     }
837   }
838
839   return Dali::Property(mImpl->mRenderer, index);
840 }
841
842 } // namespace Internal
843
844 } // namespace Toolkit
845
846 } // namespace Dali