be1739d5038ae2a7f54da7474d70d28ed113a9a5
[platform/core/uifw/dali-toolkit.git] / plugins / dali-script-v8 / src / object / handle-wrapper.cpp
1 /*
2  * Copyright (c) 2015 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 "handle-wrapper.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23
24 // INTERNAL INCLUDES
25 #include <v8-utils.h>
26 #include <shared/base-wrapped-object.h>
27 #include <shared/object-template-helper.h>
28 #include <object/property-value-wrapper.h>
29
30 namespace Dali
31 {
32
33 namespace V8Plugin
34 {
35
36 namespace // un-named name space
37 {
38
39 /**
40  * Contains a list of all functions that can be called
41  */
42 const ApiFunction HandleFunctionTable[]=
43 {
44   { "RegisterAnimatableProperty",            HandleWrapper::RegisterAnimatableProperty },
45   { "RegisterCustomProperty",                HandleWrapper::RegisterCustomProperty     },
46 };
47
48 const unsigned int HandleFunctionTableCount = sizeof(HandleFunctionTable)/sizeof(HandleFunctionTable[0]);
49 } //un-named space
50
51 /**
52  * @class Handle
53  */
54
55 HandleWrapper::HandleWrapper( BaseWrappedObject::Type type,
56     Handle handle,
57     GarbageCollectorInterface& gc ) :
58  BaseWrappedObject( type, gc ),
59  mHandle( handle )
60 {
61 }
62
63 HandleWrapper::~HandleWrapper()
64 {
65
66 }
67 HandleWrapper*  HandleWrapper::Unwrap( v8::Isolate* isolate, v8::Handle< v8::Object> obj)
68 {
69   v8::HandleScope handleScope( isolate );
70
71   v8::Local<v8::External> field = v8::Local<v8::External>::Cast( obj->GetInternalField(0) );
72   void* ptr = field->Value();
73   return static_cast< HandleWrapper *>(ptr);
74 }
75
76 // may have to do this IsUpper to intercept function calls or as function?
77 void HandleWrapper::PropertyGet( v8::Local<v8::String> propertyName,
78                                         const v8::PropertyCallbackInfo<v8::Value>& info)
79 {
80   v8::Isolate* isolate = info.GetIsolate();
81   v8::HandleScope handleScope( isolate );
82
83   // get the property name
84   std::string name = V8Utils::v8StringToStdString( propertyName );
85
86   if( std::isupper( name[0] ))
87   {
88     return;
89   }
90
91   // unwrap the object
92   HandleWrapper* handleWrapper = Unwrap( isolate, info.This() );
93   Handle handle =  handleWrapper->mHandle;
94
95   // get the property index
96   Dali::Property::Index index = handle.GetPropertyIndex( name );
97
98   if(index != Dali::Property::INVALID_INDEX)
99   {
100     Dali::Property::Value value = handle.GetProperty(index);
101
102     // Simple Dali properties (ints, strings, bools etc) are stored as JavaScript primitives (v8::Boolean ...)
103     // more complex properties (Vectors, Rectangles...) are wrapped by a JavaScript object
104     v8::Local<v8::Object> ret = PropertyValueWrapper::WrapDaliProperty( isolate, value );
105
106     info.GetReturnValue().Set( ret );
107   }
108   else
109   {
110     //  std::string error="Invalid property Get for "+name + "\n";
111     // DALI_SCRIPT_EXCEPTION( isolate, error );
112   }
113
114 }
115 void HandleWrapper::PropertySet( v8::Local<v8::String> propertyName,
116                   v8::Local<v8::Value> javaScriptValue,
117                   const v8::PropertyCallbackInfo<v8::Value>& info)
118 {
119
120   v8::Isolate* isolate = info.GetIsolate();
121   v8::HandleScope handleScope( isolate );
122
123   // get the property name
124   std::string name = V8Utils::v8StringToStdString( propertyName );
125
126   // try to filter out function calls before going to the property system
127   // @todo use installed functions to generate a map
128   if( ( name.compare(0,2,"is") == 0 )  ||
129       ( name.compare(0,3,"get") == 0 ) ||
130       ( name.compare(0,3,"add") == 0 ) ||
131       ( name.compare(0,3,"set") == 0 ) ||
132       ( name.compare(0,3,"get") == 0 ) ||
133       ( name.compare(0,4,"find") == 0 ) ||
134       ( name.compare(0,6,"remove") == 0 )
135      )
136   {
137     //
138     return;
139   }
140   // unwrap the object
141   HandleWrapper* handleWrapper = Unwrap( isolate, info.This() );
142   if( !handleWrapper )
143   {
144     // printf("setting property name %s \n", name.c_str());
145     return;
146   }
147
148  // DALI_ASSERT_DEBUG( handleWrapper && "not a dali object");
149   Handle handle =  handleWrapper->mHandle;
150
151   Dali::Property::Index index = handle.GetPropertyIndex( name );
152
153   if(index != Dali::Property::INVALID_INDEX)
154   {
155     Dali::Property::Type type = handle.GetPropertyType(index);
156
157     // we know the type we want to set ( int, vector, etc..)
158     // try and convert the javascript value in to the type we want.
159     Dali::Property::Value value = PropertyValueWrapper::ExtractPropertyValue( isolate, javaScriptValue, type);
160
161     if( Dali::Property::NONE == value.GetType() )
162       {
163         std::stringstream msg;
164         msg << "Invalid property Set: '";
165         msg << name;
166         msg << "(Index = ";
167         msg << index;
168         msg << ")";
169         msg << "' Cannot convert value to correct type: (";
170         msg << type;
171         msg << ")";
172         msg << Dali::PropertyTypes::GetName(type);
173         DALI_SCRIPT_EXCEPTION( isolate, msg.str().c_str());
174       }
175       else
176       {
177         handle.SetProperty( index, value );
178       }
179   }
180   else
181   {
182     std::string error="Invalid property Set for "+name + "\n";
183     DALI_SCRIPT_EXCEPTION( isolate, error );
184   }
185 }
186
187 void HandleWrapper::AddInterceptsToTemplate( v8::Isolate* isolate, v8::Local<v8::ObjectTemplate>& objTemplate )
188 {
189   v8::HandleScope handleScope( isolate );
190
191   objTemplate->SetNamedPropertyHandler( HandleWrapper::PropertyGet, HandleWrapper::PropertySet);
192
193   // add function properties
194   ObjectTemplateHelper::InstallFunctions( isolate, objTemplate, HandleFunctionTable, HandleFunctionTableCount );
195
196   ObjectTemplateHelper::AddSignalConnectAndDisconnect( isolate, objTemplate );
197
198 }
199
200 /**
201  * Register a new animatable property.
202  *
203  * The object should support dynamic properties.
204  * Property names are expected to be unique, but this is not enforced.
205  * Property indices are unique to each registered custom property in a given object.
206  * returns dali.PROPERTY_INVALID_INDEX if registration failed. This can happen if you try
207  * to register animatable property on an object that does not have scene graph object.
208  *
209  * @method registerAnimatableProperty
210  * @for Handle
211  * @param {string} name The name of the property.
212  * @param {Object} propertyValue The new value of the property.
213  * @return {integer} The index of the property or dali.PROPERTY_INVALID_INDEX if registration failed
214  * @example
215  *
216  *     var morphPropertyIndex = actor.registerAnimatableProperty("uMorphAmount", 0.0f);
217  *     var fadeColorPropertyIndex = handle.registerAnimatableProperty("uFadeColor", [1.0, 0.0, 0.0, 1.0]);
218  *
219  */
220 void HandleWrapper::RegisterAnimatableProperty( const v8::FunctionCallbackInfo< v8::Value >& args )
221 {
222   v8::Isolate* isolate = args.GetIsolate();
223   v8::HandleScope handleScope( isolate );
224
225   // unwrap the object
226   HandleWrapper* handleWrapper = Unwrap( isolate, args.This() );
227   if( !handleWrapper )
228   {
229     return;
230   }
231
232   Handle handle =  handleWrapper->mHandle;
233
234   bool found( false );
235   std::string propertyName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args );
236   if( !found )
237   {
238     DALI_SCRIPT_EXCEPTION( isolate, "bad property name parameter" );
239     return;
240   }
241
242   found = false;
243   Dali::Property::Value daliPropertyValue = V8Utils::GetPropertyValueParameter(PARAMETER_1, found, isolate, args );
244   if( !found || Dali::Property::NONE == daliPropertyValue.GetType() )
245   {
246     DALI_SCRIPT_EXCEPTION( isolate, "bad property value parameter" );
247     return;
248   }
249   else
250   {
251     args.GetReturnValue().Set( v8::Integer::New( isolate, handle.RegisterProperty(propertyName, daliPropertyValue) ) );
252   }
253 }
254
255 /**
256  * Register a new custom property.
257  *
258  * The object should support dynamic properties.
259  * Property names must be unused.
260  * Property indices are unique to each registered custom property in a given object.
261  * Properties can be set as non animatable using property attributes.
262  * returns dali.PROPERTY_INVALID_INDEX if registration failed.
263  *
264  * @method registerCustomProperty
265  * @for Handle
266  * @param {string} name The name of the property.
267  * @param {Object} propertyValue The new value of the property.
268  * @param {integer} accessMode The property access mode (writable, animatable etc).
269  * @return {integer} The index of the property or dali.PROPERTY_INVALID_INDEX if registration failed
270  * @example
271  *
272  *     // access mode is one of the following
273  *     dali.PROPERTY_READ_ONLY
274  *     dali.PROPERTY_READ_WRITE
275  *     dali.PROPERTY_ANIMATABLE
276  *
277  *     var cellIndexPropertyIndex = actor.registerCustomProperty("cellIndex", 2, dali.PROPERTY_READ_WRITE);
278  *     var myCustomPropertyIndex = handle.registerCustomProperty("myCustomProperty", [10.0, 25.0, 0.0], dali.PROPERTY_READ_ONLY);
279  *
280  */
281 void HandleWrapper::RegisterCustomProperty( const v8::FunctionCallbackInfo< v8::Value >& args )
282 {
283   v8::Isolate* isolate = args.GetIsolate();
284   v8::HandleScope handleScope( isolate );
285
286   // unwrap the object
287   HandleWrapper* handleWrapper = Unwrap( isolate, args.This() );
288   if( !handleWrapper )
289   {
290     return;
291   }
292
293   Handle handle =  handleWrapper->mHandle;
294
295   bool found( false );
296   std::string propertyName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args );
297   if( !found )
298   {
299     DALI_SCRIPT_EXCEPTION( isolate, "bad property name parameter" );
300     return;
301   }
302
303   found = false;
304   Dali::Property::Value daliPropertyValue = V8Utils::GetPropertyValueParameter(PARAMETER_1, found, isolate, args );
305   if( !found || Dali::Property::NONE == daliPropertyValue.GetType() )
306   {
307     DALI_SCRIPT_EXCEPTION( isolate, "bad property value parameter" );
308     return;
309   }
310
311   found = false;
312   int accessMode = V8Utils::GetIntegerParameter( PARAMETER_2, found, isolate, args, 0 /* default */);
313   if( !found )
314   {
315     DALI_SCRIPT_EXCEPTION( isolate, "invalid access mode parameter" );
316     return;
317   }
318   else
319   {
320     args.GetReturnValue().Set( v8::Integer::New( isolate, handle.RegisterProperty( propertyName, daliPropertyValue, static_cast<Property::AccessMode>(accessMode) ) ) );
321   }
322 }
323
324 } // namespace V8Plugin
325
326 } // namespace Dali