Merge "DALi Version 1.9.12" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / gradient / gradient-visual.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 "gradient-visual.h"
20
21 // EXTERNAL INCLUDES
22 #include <typeinfo>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/common/dali-vector.h>
25 #include <dali/public-api/images/buffer-image.h>
26 #include <dali/public-api/object/property-array.h>
27 #include <dali/devel-api/scripting/enum-helper.h>
28 #include <dali/devel-api/scripting/scripting.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
32 #include <dali-toolkit/public-api/visuals/visual-properties.h>
33 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
34 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
35 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
36 #include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
37 #include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
38 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
39
40 namespace Dali
41 {
42
43 namespace Toolkit
44 {
45
46 namespace Internal
47 {
48
49 namespace
50 {
51
52 DALI_ENUM_TO_STRING_TABLE_BEGIN( UNITS )
53 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX )
54 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, USER_SPACE )
55 DALI_ENUM_TO_STRING_TABLE_END( UNITS )
56
57 DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_METHOD )
58 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, PAD )
59 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REFLECT )
60 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REPEAT )
61 DALI_ENUM_TO_STRING_TABLE_END( SPREAD_METHOD )
62
63 // uniform names
64 const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
65
66 // default offset value
67 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
68 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
69
70 VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[][4] =
71 {
72   {
73     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
74     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
75     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
76     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER
77   },
78   {
79     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
80     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
81     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
82     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER
83   }
84 };
85
86 const char* VERTEX_SHADER[] =
87 {
88 // vertex shader for gradient units as OBJECT_BOUNDING_BOX
89 DALI_COMPOSE_SHADER(
90   attribute mediump vec2 aPosition;\n
91   uniform highp   mat4 uMvpMatrix;\n
92   uniform mediump vec3 uSize;\n
93   uniform mediump mat3 uAlignmentMatrix;\n
94   varying mediump vec2 vTexCoord;\n
95   \n
96
97   //Visual size and offset
98   uniform mediump vec2 offset;\n
99   uniform mediump vec2 size;\n
100   uniform mediump vec4 offsetSizeMode;\n
101   uniform mediump vec2 origin;\n
102   uniform mediump vec2 anchorPoint;\n
103
104   vec4 ComputeVertexPosition()\n
105   {\n
106     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
107     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
108     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
109   }\n
110
111   void main()\n
112   {\n
113     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
114     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
115     \n
116     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
117   }\n
118 ),
119
120 // vertex shader for gradient units as USER_SPACE
121 DALI_COMPOSE_SHADER(
122   attribute mediump vec2 aPosition;\n
123   uniform highp   mat4 uMvpMatrix;\n
124   uniform mediump vec3 uSize;\n
125   uniform mediump mat3 uAlignmentMatrix;\n
126   varying mediump vec2 vTexCoord;\n
127   \n
128
129   //Visual size and offset
130   uniform mediump vec2 offset;\n
131   uniform mediump vec2 size;\n
132   uniform mediump vec4 offsetSizeMode;\n
133   uniform mediump vec2 origin;\n
134   uniform mediump vec2 anchorPoint;\n
135
136   vec4 ComputeVertexPosition()\n
137   {\n
138     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
139     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
140     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
141   }\n
142
143   void main()\n
144   {\n
145     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
146     vertexPosition.xyz *= uSize;\n
147     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
148     \n
149     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
150   }\n
151 ),
152
153 // vertex shader for gradient units as OBJECT_BOUNDING_BOX with corner radius
154 DALI_COMPOSE_SHADER(
155   attribute mediump vec2 aPosition;\n
156   uniform highp   mat4 uMvpMatrix;\n
157   uniform mediump vec3 uSize;\n
158   uniform mediump mat3 uAlignmentMatrix;\n
159   varying mediump vec2 vTexCoord;\n
160   varying mediump vec2 vPosition;\n
161   varying mediump vec2 vRectSize;\n
162   \n
163   //Visual size and offset
164   uniform mediump vec2 offset;\n
165   uniform mediump vec2 size;\n
166   uniform mediump vec4 offsetSizeMode;\n
167   uniform mediump vec2 origin;\n
168   uniform mediump vec2 anchorPoint;\n
169   uniform mediump float cornerRadius;\n
170
171   vec4 ComputeVertexPosition()\n
172   {\n
173     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
174     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
175     vRectSize = visualSize * 0.5 - cornerRadius;\n
176     vPosition = aPosition * visualSize;\n
177     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
178   }\n
179
180   void main()\n
181   {\n
182     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
183     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
184     \n
185     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
186   }\n
187 ),
188
189 // vertex shader for gradient units as USER_SPACE with corner radius
190 DALI_COMPOSE_SHADER(
191   attribute mediump vec2 aPosition;\n
192   uniform highp   mat4 uMvpMatrix;\n
193   uniform mediump vec3 uSize;\n
194   uniform mediump mat3 uAlignmentMatrix;\n
195   varying mediump vec2 vTexCoord;\n
196   varying mediump vec2 vPosition;\n
197   varying mediump vec2 vRectSize;\n
198   \n
199   //Visual size and offset
200   uniform mediump vec2 offset;\n
201   uniform mediump vec2 size;\n
202   uniform mediump vec4 offsetSizeMode;\n
203   uniform mediump vec2 origin;\n
204   uniform mediump vec2 anchorPoint;\n
205   uniform mediump float cornerRadius;\n
206
207   vec4 ComputeVertexPosition()\n
208   {\n
209     vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
210     vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
211     vRectSize = visualSize * 0.5 - cornerRadius;\n
212     vPosition = aPosition * visualSize;\n
213     return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
214   }\n
215
216   void main()\n
217   {\n
218     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
219     vertexPosition.xyz *= uSize;\n
220     gl_Position = uMvpMatrix * ComputeVertexPosition();\n
221     \n
222     vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
223   }\n
224 )
225 };
226
227 const char* FRAGMENT_SHADER[] =
228 {
229 // fragment shader for linear gradient
230 DALI_COMPOSE_SHADER(
231   uniform sampler2D sTexture;\n // sampler1D?
232   uniform lowp vec4 uColor;\n
233   uniform lowp vec3 mixColor;\n
234   varying mediump vec2 vTexCoord;\n
235   \n
236   void main()\n
237   {\n
238     gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
239   }\n
240 ),
241
242 // fragment shader for radial gradient
243 DALI_COMPOSE_SHADER(
244   uniform sampler2D sTexture;\n // sampler1D?
245   uniform lowp vec4 uColor;\n
246   uniform lowp vec3 mixColor;\n
247   varying mediump vec2 vTexCoord;\n
248   \n
249   void main()\n
250   {\n
251     gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
252   }\n
253 ),
254
255 // fragment shader for linear gradient with corner radius
256 DALI_COMPOSE_SHADER(
257   uniform sampler2D sTexture;\n // sampler1D?
258   uniform lowp vec4 uColor;\n
259   uniform lowp vec3 mixColor;\n
260   uniform mediump float cornerRadius;\n
261   varying mediump vec2 vTexCoord;\n
262   varying mediump vec2 vPosition;\n
263   varying mediump vec2 vRectSize;\n
264   \n
265   void main()\n
266   {\n
267     mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - cornerRadius;\n
268     gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
269     gl_FragColor *= 1.0 - smoothstep( -1.0, 1.0, dist );\n
270   }\n
271 ),
272
273 // fragment shader for radial gradient with corner radius
274 DALI_COMPOSE_SHADER(
275   uniform sampler2D sTexture;\n // sampler1D?
276   uniform lowp vec4 uColor;\n
277   uniform lowp vec3 mixColor;\n
278   uniform mediump float cornerRadius;\n
279   varying mediump vec2 vTexCoord;\n
280   varying mediump vec2 vPosition;\n
281   varying mediump vec2 vRectSize;\n
282   \n
283   void main()\n
284   {\n
285     mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - cornerRadius;\n
286     gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
287     gl_FragColor *= 1.0 - smoothstep( -1.0, 1.0, dist );\n
288   }\n
289 )
290 };
291
292 Dali::WrapMode::Type GetWrapMode( Toolkit::GradientVisual::SpreadMethod::Type spread )
293 {
294   switch(spread)
295   {
296     case Toolkit::GradientVisual::SpreadMethod::REPEAT:
297     {
298       return Dali::WrapMode::REPEAT;
299     }
300     case Toolkit::GradientVisual::SpreadMethod::REFLECT:
301     {
302       return Dali::WrapMode::MIRRORED_REPEAT;
303     }
304     case Toolkit::GradientVisual::SpreadMethod::PAD:
305     default:
306     {
307       return Dali::WrapMode::CLAMP_TO_EDGE;
308     }
309   }
310 }
311
312 } // unnamed namespace
313
314 GradientVisualPtr GradientVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
315 {
316   GradientVisualPtr gradientVisualPtr( new GradientVisual( factoryCache ) );
317   gradientVisualPtr->SetProperties( properties );
318   return gradientVisualPtr;
319 }
320
321 GradientVisual::GradientVisual( VisualFactoryCache& factoryCache )
322 : Visual::Base( factoryCache, Visual::FittingMode::FILL ),
323   mGradientType( LINEAR ),
324   mIsOpaque( true )
325 {
326   mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
327 }
328
329 GradientVisual::~GradientVisual()
330 {
331 }
332
333 void GradientVisual::DoSetProperties( const Property::Map& propertyMap )
334 {
335   Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
336
337   Property::Value* unitsValue = propertyMap.Find( Toolkit::GradientVisual::Property::UNITS, UNITS_NAME );
338   if( unitsValue )
339   {
340     Scripting::GetEnumerationProperty( *unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits );
341   }
342
343   mGradientType = LINEAR;
344   if( propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME ) )
345   {
346     mGradientType = RADIAL;
347   }
348
349   if( NewGradient( mGradientType, propertyMap ) )
350   {
351     mGradient->SetGradientUnits( gradientUnits );
352     mGradientTransform = mGradient->GetAlignmentTransform();
353   }
354   else
355   {
356     DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientVisual object\n" );
357   }
358 }
359
360 void GradientVisual::OnSetTransform()
361 {
362   if( mImpl->mRenderer )
363   {
364     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
365   }
366 }
367
368 void GradientVisual::DoSetOnStage( Actor& actor )
369 {
370   InitializeRenderer();
371
372   actor.AddRenderer( mImpl->mRenderer );
373
374   // Gradient Visual generated and ready to display
375   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
376 }
377
378 void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
379 {
380   map.Clear();
381   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT );
382   map.Insert( Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits() );
383   map.Insert( Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod() );
384
385   const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
386   Property::Array offsets;
387   Property::Array colors;
388   for( unsigned int i=0; i<stops.Count(); i++ )
389   {
390     offsets.PushBack( stops[i].mOffset );
391     if( EqualsZero(stops[i].mStopColor.a) )
392     {
393       colors.PushBack( Vector4::ZERO );
394     }
395     else
396     {
397       colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
398                                 stops[i].mStopColor.g / stops[i].mStopColor.a,
399                                 stops[i].mStopColor.b / stops[i].mStopColor.a,
400                                 stops[i].mStopColor.a));
401     }
402   }
403
404   map.Insert( Toolkit::GradientVisual::Property::STOP_OFFSET, offsets );
405   map.Insert( Toolkit::GradientVisual::Property::STOP_COLOR, colors );
406
407   if( &typeid( *mGradient ) == &typeid(LinearGradient) )
408   {
409     LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
410     map.Insert( Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition() );
411     map.Insert( Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition() );
412   }
413   else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
414   {
415     RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
416     map.Insert( Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter() );
417     map.Insert( Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius() );
418   }
419 }
420
421 void GradientVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
422 {
423   // Do nothing
424 }
425
426 void GradientVisual::InitializeRenderer()
427 {
428   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
429
430   Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
431   int roundedCorner = IsRoundedCornerRequired() ? 1 : 0;
432   VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[mGradientType][gradientUnits + roundedCorner * 2];
433   Shader shader = mFactoryCache.GetShader( shaderType );
434   if( !shader )
435   {
436     shader = Shader::New( VERTEX_SHADER[gradientUnits + roundedCorner * 2], FRAGMENT_SHADER[ mGradientType + roundedCorner * 2 ] );
437     mFactoryCache.SaveShader( shaderType, shader );
438   }
439
440   //Set up the texture set
441   TextureSet textureSet = TextureSet::New();
442   Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
443   textureSet.SetTexture( 0u, lookupTexture );
444   Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
445   Sampler sampler = Sampler::New();
446   sampler.SetWrapMode(  wrap, wrap  );
447   textureSet.SetSampler( 0u, sampler );
448
449   mImpl->mRenderer = Renderer::New( geometry, shader );
450   mImpl->mRenderer.SetTextures( textureSet );
451
452   // If opaque then no need to have blending
453   if( mIsOpaque )
454   {
455     mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
456   }
457
458   mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
459
460   //Register transform properties
461   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
462 }
463
464 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
465 {
466   if( gradientType == LINEAR )
467   {
468     Property::Value* startPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME );
469     Property::Value* endPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME );
470     Vector2 startPosition;
471     Vector2 endPosition;
472
473     if( startPositionValue && startPositionValue->Get(startPosition)
474      && endPositionValue && endPositionValue->Get( endPosition ) )
475     {
476       mGradient = new LinearGradient( startPosition, endPosition );
477     }
478     else
479     {
480       return false;
481     }
482   }
483   else // type==RADIAL
484   {
485     Property::Value* centerValue = propertyMap.Find( Toolkit::GradientVisual::Property::CENTER, CENTER_NAME );
486     Property::Value* radiusValue = propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME );
487     Vector2 center;
488     float radius;
489     if( centerValue && centerValue->Get(center)
490         && radiusValue && radiusValue->Get(radius) )
491     {
492       mGradient = new RadialGradient( center, radius );
493     }
494     else
495     {
496       return false;
497     }
498   }
499
500   unsigned int numValidStop = 0u;
501   Property::Value* stopOffsetValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME );
502   Property::Value* stopColorValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME );
503   if( stopColorValue )
504   {
505     Vector<float> offsetArray;
506     Property::Array* colorArray = stopColorValue->GetArray();
507     if( colorArray )
508     {
509       GetStopOffsets( stopOffsetValue, offsetArray );
510       unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
511                              offsetArray.Count() : colorArray->Count();
512       Vector4 color;
513       for( unsigned int i=0; i<numStop; i++ )
514       {
515         if( (colorArray->GetElementAt(i)).Get(color) )
516         {
517           mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
518           numValidStop++;
519           if( ! Equals( color.a, 1.0f, Math::MACHINE_EPSILON_1 ) )
520           {
521             mIsOpaque = false;
522           }
523         }
524       }
525     }
526   }
527
528   if( numValidStop < 1u ) // no valid stop
529   {
530     return false;
531   }
532
533   Property::Value* spread = propertyMap.Find( Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME );
534   // The default spread method is PAD. Only need to set new spread if it's anything else.
535   if( spread )
536   {
537     Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
538     if( Scripting::GetEnumerationProperty( *spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod ) )
539     {
540       mGradient->SetSpreadMethod( spreadMethod );
541     }
542   }
543
544   return true;
545 }
546
547 void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
548 {
549
550   if ( value ) // Only check valve type if a valid Property has been passed in
551   {
552     switch ( value->GetType() )
553     {
554       case Property::VECTOR2:
555       {
556         Vector2 offset2;
557         value->Get( offset2 );
558         stopOffsets.PushBack( offset2.x );
559         stopOffsets.PushBack( offset2.y );
560         break;
561       }
562       case Property::VECTOR3:
563       {
564         Vector3 offset3;
565         value->Get( offset3 );
566         stopOffsets.PushBack( offset3.x );
567         stopOffsets.PushBack( offset3.y );
568         stopOffsets.PushBack( offset3.z );
569         break;
570       }
571       case Property::VECTOR4:
572       {
573         Vector4 offset4;
574         value->Get( offset4 );
575         stopOffsets.PushBack( offset4.x );
576         stopOffsets.PushBack( offset4.y );
577         stopOffsets.PushBack( offset4.z );
578         stopOffsets.PushBack( offset4.w );
579         break;
580       }
581       case Property::ARRAY:
582       {
583         Property::Array* offsetArray = value->GetArray();
584         if( offsetArray )
585         {
586           unsigned int numStop = offsetArray->Count();
587           float offset;
588           for( unsigned int i=0; i<numStop; i++ )
589           {
590             if( offsetArray->GetElementAt(i).Get(offset) )
591             {
592               stopOffsets.PushBack( offset );
593             }
594           }
595         }
596         break;
597       }
598       default:
599       {
600         DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
601         // Unsupported Type
602       }
603     }
604   }
605
606   if ( stopOffsets.Empty() )
607   {
608     // Set default offset if none set by Property system, need a minimum and maximum
609     stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
610     stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
611   }
612 }
613
614 } // namespace Internal
615
616 } // namespace Toolkit
617
618 } // namespace Dali