Merge "Added generic signal binding for toolkit controls in JavaScript" into devel...
[platform/core/uifw/dali-toolkit.git] / plugins / dali-script-v8 / src / dali-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 "dali-wrapper.h"
20
21 // INTERNAL INCLUDES
22 #include <v8-utils.h>
23 #include <object/property-value-wrapper.h>
24 #include <dali/integration-api/debug.h>
25 #include <actors/actor-wrapper.h>
26 #include <stage/stage-wrapper.h>
27 #include <image/image-wrapper.h>
28 #include <animation/linear-constrainer-wrapper.h>
29 #include <animation/path-constrainer-wrapper.h>
30 #include <animation/path-wrapper.h>
31 #include <animation/animation-wrapper.h>
32 #include <events/pan-gesture-detector-wrapper.h>
33 #include <shader-effects/shader-effect-wrapper.h>
34 #include <object/property-buffer-wrapper.h>
35 #include <rendering/geometry-wrapper.h>
36 #include <rendering/material-wrapper.h>
37 #include <rendering/renderer-wrapper.h>
38 #include <rendering/shader-wrapper.h>
39 #include <rendering/sampler-wrapper.h>
40 #include <shared/object-template-helper.h>
41 #include <constants/constants-wrapper.h>
42 #include <toolkit/builder/builder-wrapper.h>
43 #include <toolkit/focus-manager/keyboard-focus-manager-wrapper.h>
44
45
46 namespace Dali
47 {
48
49 namespace V8Plugin
50 {
51
52 namespace
53 {
54 /**
55  * This string defines how the global DALi object/namespace is used from JavaScript
56  * E.g. new dali.Image or dali.stage.add( )
57  */
58 const char* const DALI_API_NAME = "dali";
59
60 /**
61  * lookup table for setting up function calls for creating Dali objects
62  * e.g.  new dali.TextActor()
63  */
64 const ApiFunction ConstructorFunctionTable[]=
65 {
66     { "Rotation",           PropertyValueWrapper::NewRotation},
67     { "Matrix",             PropertyValueWrapper::NewMatrix},
68     { "Path",               PathWrapper::NewPath },
69     { "PathConstrainer",    PathConstrainerWrapper::NewPathConstrainer},
70     { "LinearConstrainer",  LinearConstrainerWrapper::NewLinearConstrainer},
71     { "Actor",              ActorWrapper::NewActor },
72     { "ImageActor",         ActorWrapper::NewActor },
73     { "CameraActor",        ActorWrapper::NewActor },
74     { "Layer",              ActorWrapper::NewActor },
75     { "Control",            ActorWrapper::NewControl },
76     { "ResourceImage",      ImageWrapper::NewImage },
77     { "BufferImage",        ImageWrapper::NewImage },
78     { "NinePatchImage",     ImageWrapper::NewImage },
79     { "FrameBufferImage",   ImageWrapper::NewImage },
80     { "Animation",          AnimationWrapper::NewAnimation},
81     { "ShaderEffect",       ShaderEffectWrapper::NewShaderEffect},
82     { "Shader",             ShaderWrapper::NewShader},
83     { "Sampler",            SamplerWrapper::NewSampler},
84     { "Material",           MaterialWrapper::NewMaterial},
85     { "Geometry",           GeometryWrapper::NewGeometry},
86     { "Renderer",           RendererWrapper::NewRenderer},
87     { "PropertyBuffer",     PropertyBufferWrapper::NewPropertyBuffer},
88     { "Builder",            BuilderWrapper::NewBuilder},
89     { "PanGestureDetector", PanGestureDetectorWrapper::NewPanGestureDetector},
90
91 };
92
93 const unsigned int PropertyFunctionTableCount = sizeof(ConstructorFunctionTable)/sizeof(ConstructorFunctionTable[0]);
94
95 void FatalErrorCallback(const char* location, const char* message)
96 {
97   DALI_LOG_ERROR("%s, %s \n",location,message);
98   DALI_ASSERT_ALWAYS( 0 && "V8 fatal error");
99 }
100
101 #if defined(DEBUG_ENABLED)
102 // default to verbose logging
103 Integration::Log::Filter* gLogExecuteFilter( Integration::Log::Filter::New(Debug::Verbose, false, "EXECUTE_JAVASCRIPT") );
104 #endif
105 } // un-named name space
106
107
108
109 bool DaliWrapper::mInstanceCreated = false;
110 DaliWrapper* DaliWrapper::mWrapper = NULL;
111
112 DaliWrapper::DaliWrapper( RunMode runMode, v8::Isolate* isolate )
113 :mIsolate( isolate ),
114  mRunMode(runMode)
115 {
116 }
117
118 DaliWrapper::~DaliWrapper()
119 {
120   mInstanceCreated = false;
121 }
122
123 DaliWrapper& DaliWrapper::Get()
124 {
125   if( !mInstanceCreated )
126   {
127     mWrapper = new DaliWrapper( RUNNING_STANDALONE, NULL );
128
129     mInstanceCreated = true;
130
131     mWrapper->InitializeStandAlone();
132
133   }
134   return *mWrapper;
135 }
136
137 v8::Local<v8::Object> DaliWrapper::CreateWrapperForNodeJS( v8::Isolate* isolate )
138 {
139   v8::EscapableHandleScope handleScope( isolate);
140
141   mInstanceCreated = true;
142
143   mWrapper = new DaliWrapper( RUNNING_IN_NODE_JS, isolate );
144
145   v8::Local<v8::Object> dali = mWrapper->CreateDaliObject();
146
147   // As we running inside node, we already have an isolate and context
148   return handleScope.Escape( dali );
149 }
150
151 v8::Local<v8::Object>  DaliWrapper::CreateDaliObject()
152 {
153   v8::EscapableHandleScope handleScope( mIsolate  );
154
155   // Create dali object used for creating objects, and accessing constant values
156   // e.g. var x =  new dali.Actor(), or var col = dali.COLOR_RED;
157
158   v8::Local<v8::ObjectTemplate> daliObjectTemplate = NewDaliObjectTemplate( mIsolate );
159
160   // add dali.staqe
161   v8::Local<v8::Object> stageObject = StageWrapper::WrapStage( mIsolate, Stage::GetCurrent() );
162   daliObjectTemplate->Set( v8::String::NewFromUtf8( mIsolate, "stage") , stageObject );
163
164   v8::Local<v8::Object> keyboardObject = KeyboardFocusManagerWrapper::WrapKeyboardFocusManager( mIsolate,Toolkit::KeyboardFocusManager::Get() );
165   daliObjectTemplate->Set( v8::String::NewFromUtf8( mIsolate, "keyboardFocusManager") , keyboardObject );
166
167
168   //create an instance of the template
169   v8::Local<v8::Object> daliObject = daliObjectTemplate->NewInstance();
170
171   ConstantsWrapper::AddDaliConstants( mIsolate, daliObject);
172
173   daliObject->Set( v8::String::NewFromUtf8( mIsolate,  "V8_VERSION") ,v8::String::NewFromUtf8( mIsolate, v8::V8::GetVersion() ));
174
175   return handleScope.Escape( daliObject  );
176 }
177
178
179 void DaliWrapper::SetFlagsFromString(const std::string &flags)
180 {
181   v8::V8::SetFlagsFromString(flags.c_str(), flags.size());
182 }
183
184 void DaliWrapper::Shutdown()
185 {
186   // if we're running inside node then we don't have ownership of the context
187   if( mRunMode == RUNNING_IN_NODE_JS )
188   {
189     return;
190   }
191
192   DALI_LOG_WARNING("Destroying V8 DALi context\n");
193
194   if( !mContext.IsEmpty())
195   {
196     v8::HandleScope handleScope( mIsolate );
197     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(mIsolate, mContext);
198     context->Exit();   // exit the context
199     mContext.Reset();  // destroys the context
200   }
201 }
202
203 bool DaliWrapper::ExecuteBuffer(const std::string &sourceCode, const std::string &sourceFileName)
204 {
205   return mModuleLoader.ExecuteScript( mIsolate,  sourceCode, sourceFileName );
206 }
207
208 bool DaliWrapper::ExecuteFile( const std::string& sourceFileName )
209 {
210   DALI_LOG_INFO( gLogExecuteFilter, Debug::Verbose, "Executing source file %s \n",sourceFileName.c_str() );
211
212   return mModuleLoader.ExecuteScriptFromFile( mIsolate,  sourceFileName );
213 }
214
215 GarbageCollectorInterface& DaliWrapper::GetDaliGarbageCollector()
216 {
217   return mGarbageCollector;
218 }
219
220 void DaliWrapper::ApplyGlobalObjectsToContext( v8::Local<v8::Context> context )
221 {
222   v8::HandleScope handleScope( mIsolate );
223
224   // Add global objects ( functions/ values ) e.g. log function
225   // create a console.log and console.error functions
226   v8::Local<v8::ObjectTemplate> consoleObjectTemplate = v8::ObjectTemplate::New( mIsolate );
227   consoleObjectTemplate->Set( v8::String::NewFromUtf8( mIsolate, "log"),   v8::FunctionTemplate::New( mIsolate, V8Utils::Log));
228   consoleObjectTemplate->Set( v8::String::NewFromUtf8( mIsolate, "error"), v8::FunctionTemplate::New( mIsolate, V8Utils::LogError));
229
230   context->Global()->Set( v8::String::NewFromUtf8( mIsolate, "console"), consoleObjectTemplate->NewInstance() );
231
232   // add require functionality
233   context->Global()->Set( v8::String::NewFromUtf8( mIsolate, "require"), v8::FunctionTemplate::New( mIsolate, DaliWrapper::Require)->GetFunction());
234
235   // Create the Dali object
236   // @todo consider forcing developers to perform require('dali') if we want to avoid polluting the global namespace
237   v8::Local<v8::Object> daliObject = CreateDaliObject();
238
239   // allow developers to require('dali'); // this is to maintain compatibility with node.js where dali is not part of the global namespace
240   mModuleLoader.StorePreBuiltModule( mIsolate, daliObject, DALI_API_NAME );
241
242   context->Global()->Set( v8::String::NewFromUtf8( mIsolate, DALI_API_NAME),daliObject );
243
244 }
245
246 void DaliWrapper::InitializeStandAlone()
247 {
248   if( !mIsolate )
249   {
250     v8::V8::InitializeICU();
251
252     v8::V8::Initialize();
253
254     // default isolate removed from V8 version 3.27.1 and beyond.
255     mIsolate = v8::Isolate::New();
256
257     mIsolate->Enter();
258
259     v8::V8::SetFatalErrorHandler( FatalErrorCallback );
260   }
261
262   // if context is null, create it and add dali object to the global object.
263   if( mContext.IsEmpty())
264   {
265      v8::HandleScope handleScope( mIsolate );
266
267      // create a new context.
268      // Isolate = isolated copy of the V8 including a heap manager, a garbage collector
269      // Only 1 thread can access a single Isolate at a given time. However, multiple Isolates can be run in parallel.
270      // Context = multiple contexts can exist in a given Isolate, and share data between contexts
271      v8::Local<v8::Context> context  = v8::Context::New( mIsolate );
272
273      context->Enter();
274
275      // Apply global objects like dali and console to the context
276      ApplyGlobalObjectsToContext(context);
277
278      mContext.Reset( mIsolate, context);
279   }
280
281   DALI_LOG_INFO( gLogExecuteFilter, Debug::Verbose, "V8 Library %s loaded \n", v8::V8::GetVersion() );
282 }
283
284
285 v8::Handle<v8::ObjectTemplate> DaliWrapper::NewDaliObjectTemplate( v8::Isolate* isolate )
286 {
287   v8::EscapableHandleScope handleScope( isolate );
288
289   // create the template
290   v8::Local< v8::ObjectTemplate > objTemplate = v8::ObjectTemplate::New( isolate );
291
292   // Add some value properties ( a property can be a primitive value, an object or a function).
293   objTemplate->Set( v8::String::NewFromUtf8( isolate, "BUILD"),
294                     v8::String::NewFromUtf8( isolate, "Dali binary built on:" __DATE__ ", at " __TIME__));
295
296 #ifdef DALI_DATA_READ_ONLY_DIR
297   // add the data data directory,
298   objTemplate->Set( v8::String::NewFromUtf8( isolate, "DALI_DATA_DIRECTORY"),
299                     v8::String::NewFromUtf8( isolate, DALI_DATA_READ_ONLY_DIR));
300 #endif
301   // add our constructor functions
302   ObjectTemplateHelper::InstallFunctions( isolate,
303                                           objTemplate,
304                                           ConstructorFunctionTable,
305                                           PropertyFunctionTableCount,
306                                           ObjectTemplateHelper::CONSTRUCTOR_FUNCTIONS);
307
308   return handleScope.Escape( objTemplate );
309 }
310
311 void DaliWrapper::Require(const v8::FunctionCallbackInfo< v8::Value >& args)
312 {
313   DaliWrapper& wrapper( DaliWrapper::Get() );
314   wrapper.mModuleLoader.Require( args );
315 }
316
317
318 } // namespace V8Plugin
319
320 } // namespace Dali