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