DALi Version 1.4.26
[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     // Trying to set the value for a property that is not registered yet.
183     std::stringstream msg;
184     msg << "Trying to set the value of an unregistered property: ";
185     msg << name;
186     DALI_SCRIPT_WARNING( msg.str().c_str() );
187
188     // Register the custom property automatically.
189     handle.RegisterProperty( name, PropertyValueWrapper::ExtractPropertyValue( isolate, javaScriptValue), Property::READ_WRITE );
190   }
191 }
192
193 void HandleWrapper::AddInterceptsToTemplate( v8::Isolate* isolate, v8::Local<v8::ObjectTemplate>& objTemplate )
194 {
195   v8::HandleScope handleScope( isolate );
196
197   objTemplate->SetNamedPropertyHandler( HandleWrapper::PropertyGet, HandleWrapper::PropertySet);
198
199   // add function properties
200   ObjectTemplateHelper::InstallFunctions( isolate, objTemplate, HandleFunctionTable, HandleFunctionTableCount );
201
202   ObjectTemplateHelper::AddSignalConnectAndDisconnect( isolate, objTemplate );
203
204 }
205
206 /**
207  * Register a new animatable property.
208  *
209  * The object should support dynamic properties.
210  * Property names are expected to be unique, but this is not enforced.
211  * Property indices are unique to each registered custom property in a given object.
212  * returns dali.PROPERTY_INVALID_INDEX if registration failed. This can happen if you try
213  * to register animatable property on an object that does not have scene graph object.
214  *
215  * @method registerAnimatableProperty
216  * @for Handle
217  * @param {string} name The name of the property.
218  * @param {Object} propertyValue The new value of the property.
219  * @return {integer} The index of the property or dali.PROPERTY_INVALID_INDEX if registration failed
220  * @example
221  *
222  *     var morphPropertyIndex = actor.registerAnimatableProperty("uMorphAmount", 0.0f);
223  *     var fadeColorPropertyIndex = handle.registerAnimatableProperty("uFadeColor", [1.0, 0.0, 0.0, 1.0]);
224  *
225  */
226 void HandleWrapper::RegisterAnimatableProperty( const v8::FunctionCallbackInfo< v8::Value >& args )
227 {
228   v8::Isolate* isolate = args.GetIsolate();
229   v8::HandleScope handleScope( isolate );
230
231   // unwrap the object
232   HandleWrapper* handleWrapper = Unwrap( isolate, args.This() );
233   if( !handleWrapper )
234   {
235     return;
236   }
237
238   Handle handle =  handleWrapper->mHandle;
239
240   bool found( false );
241   std::string propertyName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args );
242   if( !found )
243   {
244     DALI_SCRIPT_EXCEPTION( isolate, "bad property name parameter" );
245     return;
246   }
247
248   found = false;
249   Dali::Property::Value daliPropertyValue = V8Utils::GetPropertyValueParameter(PARAMETER_1, found, isolate, args );
250   if( !found || Dali::Property::NONE == daliPropertyValue.GetType() )
251   {
252     DALI_SCRIPT_EXCEPTION( isolate, "bad property value parameter" );
253     return;
254   }
255   else
256   {
257     args.GetReturnValue().Set( v8::Integer::New( isolate, handle.RegisterProperty(propertyName, daliPropertyValue) ) );
258   }
259 }
260
261 /**
262  * Register a new custom property.
263  *
264  * The object should support dynamic properties.
265  * Property names must be unused.
266  * Property indices are unique to each registered custom property in a given object.
267  * Properties can be set as non animatable using property attributes.
268  * returns dali.PROPERTY_INVALID_INDEX if registration failed.
269  *
270  * @method registerCustomProperty
271  * @for Handle
272  * @param {string} name The name of the property.
273  * @param {Object} propertyValue The new value of the property.
274  * @param {integer} accessMode The property access mode (writable, animatable etc).
275  * @return {integer} The index of the property or dali.PROPERTY_INVALID_INDEX if registration failed
276  * @example
277  *
278  *     // access mode is one of the following
279  *     dali.PROPERTY_READ_ONLY
280  *     dali.PROPERTY_READ_WRITE
281  *     dali.PROPERTY_ANIMATABLE
282  *
283  *     var cellIndexPropertyIndex = actor.registerCustomProperty("cellIndex", 2, dali.PROPERTY_READ_WRITE);
284  *     var myCustomPropertyIndex = handle.registerCustomProperty("myCustomProperty", [10.0, 25.0, 0.0], dali.PROPERTY_READ_ONLY);
285  *
286  */
287 void HandleWrapper::RegisterCustomProperty( const v8::FunctionCallbackInfo< v8::Value >& args )
288 {
289   v8::Isolate* isolate = args.GetIsolate();
290   v8::HandleScope handleScope( isolate );
291
292   // unwrap the object
293   HandleWrapper* handleWrapper = Unwrap( isolate, args.This() );
294   if( !handleWrapper )
295   {
296     return;
297   }
298
299   Handle handle =  handleWrapper->mHandle;
300
301   bool found( false );
302   std::string propertyName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args );
303   if( !found )
304   {
305     DALI_SCRIPT_EXCEPTION( isolate, "bad property name parameter" );
306     return;
307   }
308
309   found = false;
310   Dali::Property::Value daliPropertyValue = V8Utils::GetPropertyValueParameter(PARAMETER_1, found, isolate, args );
311   if( !found || Dali::Property::NONE == daliPropertyValue.GetType() )
312   {
313     DALI_SCRIPT_EXCEPTION( isolate, "bad property value parameter" );
314     return;
315   }
316
317   found = false;
318   int accessMode = V8Utils::GetIntegerParameter( PARAMETER_2, found, isolate, args, 0 /* default */);
319   if( !found )
320   {
321     DALI_SCRIPT_EXCEPTION( isolate, "invalid access mode parameter" );
322     return;
323   }
324   else
325   {
326     args.GetReturnValue().Set( v8::Integer::New( isolate, handle.RegisterProperty( propertyName, daliPropertyValue, static_cast<Property::AccessMode>(accessMode) ) ) );
327   }
328 }
329
330 } // namespace V8Plugin
331
332 } // namespace Dali