2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <dali/integration-api/debug.h>
28 #include <object/property-value-wrapper.h>
29 #include <actors/actor-wrapper.h>
30 #include <object/handle-wrapper.h>
31 #include <image/image-wrapper.h>
32 #include <render-tasks/render-task-wrapper.h>
33 #include <object/property-value-wrapper.h>
37 * Similar to DALI_LOG_ERROR except the PRETTY_FUNCTION
38 * is removed because it makes no sense for scripting errors.
40 #define DALI_LOG_SCRIPT_ERROR(format, args...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, format, ## args)
51 void Log(const v8::FunctionCallbackInfo< v8::Value >& args)
53 v8::HandleScope handleScope( args.GetIsolate());
56 for (int i = 0; i < args.Length(); i++)
66 v8::String::Utf8Value utf8_value( args[i] );
67 std::cout << *utf8_value;
71 void LogError(const v8::FunctionCallbackInfo< v8::Value >& args)
73 v8::HandleScope handleScope( args.GetIsolate());
76 for (int i = 0; i < args.Length(); i++)
86 v8::String::Utf8Value utf8_value( args[i] );
87 output += *utf8_value;
89 DALI_LOG_ERROR_NOFN( "JavaScript: %s",output.c_str() );
92 void GetFileContents(const std::string &fileName, std::string& contents)
94 std::ifstream t(fileName.c_str());
95 contents = std::string((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
98 void GetFileDirectory( const std::string& fileName, std::string& directory )
102 // get the position of the last slash
103 size_t pos = fileName.find_last_of("\\/");
105 // if it doesn't exist, return nothing
106 if( (std::string::npos == pos ) )
112 // check an edge case where the string ends in a forward slash "mydir/"
113 if( (pos+1) < fileName.length() )
115 directory = fileName.substr(0, pos+1);
121 void GetFileName( const std::string& fullPathName, std::string& fileName )
123 // look for last slash
124 size_t pos = fullPathName.find_last_of("\\/");
126 if( std::string::npos == pos )
128 fileName = fullPathName;
132 fileName = fullPathName.substr(pos,fileName.length());
136 void GetModuleName( const std::string& fileName, std::string& moduleName )
138 std::string fileNameNoPath;
139 GetFileName( fileName , fileNameNoPath );
140 size_t pos = fileNameNoPath.find_last_of(".");
141 if( std::string::npos == pos )
143 moduleName = fileNameNoPath;
147 moduleName = fileName.substr(0, pos );
151 void ReportException( v8::Isolate* isolate, v8::TryCatch* tryCatch)
153 v8::HandleScope handleScope( isolate );
155 v8::String::Utf8Value exception(tryCatch->Exception());
156 v8::Handle<v8::Message> message = tryCatch->Message();
158 if (message.IsEmpty())
160 // V8 didn't provide any extra information about this error; just
161 // print the exception.
162 DALI_LOG_SCRIPT_ERROR("%s\n", *exception);
167 // Print (filename):(line number): (message).
168 v8::String::Utf8Value filename(message->GetScriptResourceName());
170 DALI_LOG_SCRIPT_ERROR("\n\n====== Error found in JavaScript: ========= \n");
173 int linenum = message->GetLineNumber();
174 DALI_LOG_SCRIPT_ERROR("File: %s\n", *filename, linenum, *exception);
176 DALI_LOG_SCRIPT_ERROR("Error: :%s\n", *exception );
177 DALI_LOG_SCRIPT_ERROR("Line: :%i\n", linenum );
179 // Print line of source code.
180 v8::String::Utf8Value sourceline(message->GetSourceLine());
182 DALI_LOG_SCRIPT_ERROR("Source: %s\n", *sourceline);
184 // Print wavy underline (GetUnderline is deprecated).
186 std::stringstream msg;
188 int start = message->GetStartColumn();
189 for (int i = 0; i < start; i++)
193 int end = message->GetEndColumn();
194 for (int i = start; i < end; i++)
199 DALI_LOG_SCRIPT_ERROR(" %s\n", msg.str().c_str());
201 v8::String::Utf8Value stack_trace(tryCatch->StackTrace());
202 if (stack_trace.length() > 0)
204 DALI_LOG_SCRIPT_ERROR("%s\n", *stack_trace);
206 DALI_LOG_SCRIPT_ERROR("\n=========================================== \n");
211 std::string GetJavaScriptFunctionName( const char* functionName )
213 // @todo if we are 100% decided on lower case, go through
214 // every api and manually change the function names to lower case first character
215 std::string name( functionName );
216 name[0]=tolower( functionName[0] );
220 void Version(const v8::FunctionCallbackInfo< v8::Value >& args)
222 v8::HandleScope handleScope( args.GetIsolate());
224 v8::Handle<v8::String> ver = v8::String::NewFromUtf8(args.GetIsolate(), v8::V8::GetVersion());
226 args.GetReturnValue().Set(ver);
230 std::string v8StringToStdString( const v8::Handle<v8::Value>& value )
232 v8::String::Utf8Value utf8(value);
233 return std::string(*utf8);
237 std::string PropertyNameToJavaScriptName(const std::string& hyphenatedName)
241 ret.reserve(hyphenatedName.size());
243 bool capitlizeNext = false ;
244 for(unsigned int i = 0; i < hyphenatedName.size(); ++i)
246 char c = hyphenatedName[i];
249 capitlizeNext = true;
255 ret.push_back(std::toupper(c));
256 capitlizeNext = false;
270 std::string JavaScriptNameToPropertyName(const std::string& camelCase)
275 for(unsigned int i = 0; i < camelCase.size(); ++i)
277 if(std::isupper(camelCase[i]))
285 ret.reserve(camelCase.size() + countUpper);
287 for(unsigned int i = 0; i < camelCase.size(); ++i)
289 char c = camelCase[i];
295 ret.push_back(std::tolower(c));
306 void ScriptError( const char* function, v8::Isolate* isolate, std::string errorString )
308 v8::EscapableHandleScope scope( isolate);
309 std::string errorMsg = std::string(function) + std::string("(), ") + errorString;
311 // log out to DALI_LOG_ERROR first, so we know something has gone wrong
312 DALI_LOG_ERROR("%s \n", errorMsg.c_str() );
314 // throw a V8 exception, DALi will keep running but we will get a print out
315 // of where the error occured in the JavaScript source
316 isolate->ThrowException( v8::String::NewFromUtf8( isolate, errorMsg.c_str()) );
319 bool IsBooleanPrimitiveOrObject( const v8::Local<v8::Value>& value )
321 return ( value->IsBoolean() || value->IsBooleanObject());
324 bool GetBooleanValue( v8::Isolate* isolate, const v8::Local<v8::Value>& value )
326 v8::EscapableHandleScope scope( isolate); // may not be required.
328 if( value->IsBoolean() )
330 return value->ToBoolean()->Value();
332 else if (value->IsBooleanObject() )
334 const v8::Local<v8::BooleanObject> object = v8::Local<v8::BooleanObject>::Cast(value);
335 return object->BooleanValue();
337 DALI_SCRIPT_EXCEPTION(isolate, "no bool found");
341 bool IsNumberPrimitiveOrObject( const v8::Local<v8::Value>& value )
343 return ( value->IsNumber() || value->IsNumberObject());
346 float GetNumberValue( v8::Isolate* isolate, const v8::Local<v8::Value>& value )
348 v8::EscapableHandleScope scope( isolate); // may not be required.
350 if( value->IsNumber() )
352 return value->ToNumber()->Value();
354 else if (value->IsNumberObject() )
356 const v8::Local<v8::NumberObject> object = v8::Local<v8::NumberObject>::Cast(value);
357 return object->ValueOf();
360 DALI_SCRIPT_EXCEPTION(isolate, "no number found?");
364 bool IsStringPrimitiveOrObject( const v8::Local<v8::Value>& value )
366 return ( value->IsString() || value->IsStringObject());
369 std::string GetStringValue( v8::Isolate* isolate, const v8::Local<v8::Value>& value )
371 v8::EscapableHandleScope scope( isolate); // may not be required.
373 if( value->IsString() )
375 return V8Utils::v8StringToStdString(value);
377 else if (value->IsStringObject() )
379 const v8::Local<v8::StringObject> object = v8::Local<v8::StringObject>::Cast(value);
380 return V8Utils::v8StringToStdString( object->ValueOf() );
383 DALI_SCRIPT_EXCEPTION(isolate, "no string found?");
388 Property::Value GetPropertyValueFromObject( bool& found, v8::Isolate* isolate, const v8::Local<v8::Value >& value )
390 v8::HandleScope handleScope( isolate);
392 Property::Value daliPropertyValue;// creates a property with Property::INVALID
396 if( value->IsObject() )
398 v8::Local<v8::Object> object = v8::Handle<v8::Object>::Cast( value );
400 if( BaseWrappedObject::IsWrappedTypeAPropertyValue( object ) )
403 PropertyValueWrapper* propertyWrapper = PropertyValueWrapper::Unwrap( isolate, object );
404 return propertyWrapper->GetValue();
406 else if( value->IsArray() )
409 return PropertyValueWrapper::VectorOrMatrixFromV8Array( isolate, object);//todo check for V8 array / map?
412 else if( value->IsBoolean() )
415 v8::Local<v8::Boolean> v = value->ToBoolean();
416 return Dali::Property::Value(v->Value());
418 else if( value->IsNumber() )
421 v8::Local<v8::Number> v = value->ToNumber();
422 return Dali::Property::Value(static_cast<float>(v->Value()));
424 else if( value->IsInt32() )
427 v8::Local<v8::Int32> v = value->ToInt32();
428 return Dali::Property::Value(static_cast<int>(v->Value()));
430 else if ( value->IsUint32() )
433 v8::Local<v8::Uint32> v = value->ToUint32();
434 return Dali::Property::Value(static_cast<unsigned int>(v->Value()));
436 return daliPropertyValue;
440 Property::Map GetPropertyMapFromObject( v8::Isolate* isolate, const v8::Local<v8::Object>& object)
442 v8::Local<v8::Array> properties = object->GetPropertyNames();
443 Property::Map propertyMap; // empty map
445 for( unsigned int i = 0; i < properties->Length(); ++i)
448 v8::Local<v8::Value> key = properties->Get( i );
449 std::string keyString = v8StringToStdString( key );
452 v8::Local<v8::Value> value = object->Get( key );
453 std::string valueString = V8Utils::v8StringToStdString( value );
455 propertyMap[ keyString ] = valueString.c_str();
461 Actor GetActorFromObject( v8::Isolate* isolate, bool& found, v8::Local<v8::Object>& object)
463 v8::HandleScope handleScope( isolate);
466 if( BaseWrappedObject::IsWrappedType ( isolate, object, BaseWrappedObject::ACTOR ))
468 HandleWrapper* handleWrapper = HandleWrapper::Unwrap( isolate, object );
469 return Actor::DownCast( handleWrapper->mHandle );
475 int GetIntegerParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args, int defaultValue )
478 unsigned int length = args.Length();
479 if( index >= length )
483 if( args[ index ]->IsInt32() )
486 return args[ index ]->Int32Value();
493 float GetFloatParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args, float defaultValue )
496 unsigned int length = args.Length();
497 if( index >= length )
501 if( args[ index ]->IsNumber() )
504 return args[ index ]->NumberValue();
511 std::string GetStringParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
514 unsigned int length = args.Length();
516 if( index >= length )
518 return std::string();
520 if( args[ index ]->IsString() )
523 return v8StringToStdString( args[ index ]);
527 return std::string();
531 bool GetBooleanParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
533 v8::HandleScope handleScope( isolate);
536 unsigned int length = args.Length();
537 if( index >= length )
541 if( args[ index ]->IsBoolean() )
544 v8::Local<v8::Boolean> v = args[ index ]->ToBoolean();
553 Handle GetHandleParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
555 v8::HandleScope handleScope( isolate);
558 unsigned int length = args.Length();
559 if( index >= length )
564 if( args[ index ]->IsObject() )
566 v8::Local<v8::Object> object = args[ index ]->ToObject();
567 v8::Local<v8::External> field = v8::Local<v8::External>::Cast( object->GetInternalField(0) );
568 void* ptr = field->Value();
572 HandleWrapper* wrapper = static_cast< HandleWrapper *>(ptr);
573 return wrapper->GetHandle();
579 Vector2 GetVector2Parameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
581 v8::HandleScope handleScope( isolate);
582 unsigned int length = args.Length();
588 if( args[ index ]->IsObject() )
590 Dali::Property::Value value;
591 value = PropertyValueWrapper::ExtractPropertyValue( isolate, args[index], Dali::Property::VECTOR2 );
592 if( value.GetType() == Dali::Property::VECTOR2)
599 DALI_SCRIPT_EXCEPTION(isolate, "Missing Vector2 parameter");
605 DALI_SCRIPT_EXCEPTION(isolate, "Missing Vector2 parameter");
611 Vector2 GetVector2ParameterFrom2Float( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
613 Vector2 ret(0.0f,0.0f);
615 unsigned int argCount( args.Length() );
617 if( index+2 >= argCount )
619 DALI_SCRIPT_EXCEPTION(isolate, "Missing parameter");
623 ret.x = V8Utils::GetFloatParameter( index, bFound, isolate, args, 0.0f );
624 found = found && bFound;
625 ret.y = V8Utils::GetFloatParameter( index+1, bFound, isolate, args, 0.0f );
626 found = found && bFound;
631 Vector3 GetVector3Parameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args)
633 v8::HandleScope handleScope( isolate);
634 unsigned int argCount( args.Length() );
637 if( index < argCount )
639 if( args[ index ]->IsObject() )
641 Dali::Property::Value value;
642 value = PropertyValueWrapper::ExtractPropertyValue( isolate, args[index], Dali::Property::VECTOR3 );
643 if( value.GetType() == Dali::Property::VECTOR3)
650 DALI_SCRIPT_EXCEPTION(isolate, "Missing Vector3 parameter");
656 DALI_SCRIPT_EXCEPTION(isolate, "Missing Vector3 parameter");
663 Vector4 GetVector4Parameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args)
665 v8::HandleScope handleScope( isolate);
666 unsigned int argCount( args.Length() );
670 if( index < argCount )
672 if( args[ index ]->IsObject() )
674 Dali::Property::Value value;
675 value = PropertyValueWrapper::ExtractPropertyValue( isolate, args[index], Dali::Property::VECTOR4 );
676 if( value.GetType() == Dali::Property::VECTOR4)
683 DALI_SCRIPT_EXCEPTION(isolate, "Missing Vector4 parameter");
689 DALI_SCRIPT_EXCEPTION(isolate, "Missing Vector4 parameter");
696 Rect<int> GetRectIntParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
698 v8::HandleScope handleScope( isolate);
701 int length = args.Length() - index;
703 // if it's an array read the 2 numbers into a vector2
706 if( args[ 0 + index ]->IsInt32() &&
707 args[ 1 + index ]->IsInt32() &&
708 args[ 2 + index ]->IsInt32() &&
709 args[ 3 + index ]->IsInt32() )
712 Rect<int> rect( args[ 0 + index ]->Int32Value(),
713 args[ 1 + index ]->Int32Value(),
714 args[ 2 + index ]->Int32Value(),
715 args[ 3 + index ]->Int32Value() );
719 // this will extract a Vector4, if it is a Vector4 or a Javascript array object
720 if( args[ index ]->IsObject() )
722 Dali::Property::Value value;
723 value = PropertyValueWrapper::ExtractPropertyValue( isolate, args[index], Dali::Property::RECTANGLE );
724 if( value.GetType() == Dali::Property::RECTANGLE)
732 // @todo support vector4 as well?
737 Actor GetActorParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
739 BaseWrappedObject* wrapper = GetWrappedDaliObjectParameter( index, BaseWrappedObject::ACTOR, isolate, args);
740 ActorWrapper* actorWrapper = static_cast< ActorWrapper*>( wrapper );
744 return actorWrapper->GetActor();
752 Layer GetLayerParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
754 Actor actor = GetActorParameter( index, found, isolate, args );
755 return Layer::DownCast( actor );
758 Image GetImageParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
760 BaseWrappedObject* wrappedObject = V8Utils::GetWrappedDaliObjectParameter( index, BaseWrappedObject::IMAGE, isolate, args );
764 ImageWrapper* wrapper = static_cast< ImageWrapper *>(wrappedObject);
765 return wrapper->GetImage();
773 RenderTask GetRenderTaskParameter( unsigned int paramIndex, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
776 BaseWrappedObject* wrappedObject = V8Utils::GetWrappedDaliObjectParameter( paramIndex, BaseWrappedObject::RENDER_TASK, isolate, args );
780 RenderTaskWrapper* wrapper = static_cast< RenderTaskWrapper *>(wrappedObject);
781 return wrapper->GetRenderTask();
785 return RenderTask(); // empty handle
790 BaseWrappedObject* GetWrappedDaliObjectParameter( unsigned int index, BaseWrappedObject::Type type, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
792 v8::HandleScope handleScope( isolate);
793 unsigned int length = args.Length();
795 if( index >= length )
800 if( !args[ index ]->IsObject() )
805 v8::Local<v8::Object> object = args[ index ]->ToObject();
807 if( BaseWrappedObject::IsWrappedType ( isolate, object, type ))
809 v8::Local<v8::External> field = v8::Local<v8::External>::Cast( object->GetInternalField(0) );
810 void* ptr = field->Value();
811 BaseWrappedObject* wrapper = static_cast< BaseWrappedObject *>(ptr);
818 Property::Value GetPropertyValueParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
820 v8::HandleScope handleScope( isolate);
822 Property::Value daliPropertyValue;// creates a property with Property::INVALID
825 unsigned int length = args.Length();
827 if( index >= length )
829 return daliPropertyValue;
831 v8::Local<v8::Value > value = args[ index ];
833 return GetPropertyValueFromObject( found, isolate, value);
836 Property::Map GetPropertyMapParameter( unsigned int index, bool& found, v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
838 v8::HandleScope handleScope( isolate);
840 Property::Map propertyMap; // empty map
843 unsigned int length = args.Length();
845 if( index >= length )
850 if( !args[ index ]->IsObject() )
856 // go through each key value pair
857 v8::Local<v8::Object> obj = args[ index ]->ToObject();
859 return GetPropertyMapFromObject( isolate, obj );
863 void CreatePropertyMap( v8::Isolate* isolate, const Property::Map& map, v8::Local<v8::Object>& object )
865 v8::HandleScope handleScope( isolate);
867 // we're converting a dali property map in to a JavaScript property map
868 if( map.Count() == 0 )
873 for( unsigned int index = 0; index < map.Count() - 1; ++index )
875 const std::string& key = map.GetKey( index );
876 Property::Value& value = map.GetValue( index );
877 v8::Local<v8::Value> v8Value;
879 switch( value.GetType() )
881 case Dali::Property::FLOAT:
883 v8Value = v8::Number::New( isolate, value.Get<float>() );
886 case Dali::Property::BOOLEAN:
888 v8Value = v8::Boolean::New( isolate, value.Get<bool>());
891 case Dali::Property::INTEGER:
893 v8Value = v8::Integer::New( isolate, value.Get<int>());
896 case Dali::Property::UNSIGNED_INTEGER:
898 v8Value = v8::Integer::New( isolate, value.Get<unsigned int>());
901 case Dali::Property::STRING:
903 std::string string = value.Get< std::string >();
904 v8Value = v8::String::NewFromUtf8( isolate, string.c_str());
907 case Dali::Property::VECTOR2:
910 Vector2 vec = value.Get<Vector2>();
911 v8::Local<v8::Array> array= v8::Array::New( isolate, 2 );
912 array->Set( 0 , v8::Number::New(isolate, vec.x));
913 array->Set( 1 , v8::Number::New(isolate, vec.y));
917 case Dali::Property::VECTOR3:
920 Vector3 vec = value.Get<Vector3>();
921 v8::Local<v8::Array> array= v8::Array::New( isolate, 3 );
922 array->Set( 0 , v8::Number::New(isolate, vec.x));
923 array->Set( 1 , v8::Number::New(isolate, vec.y));
924 array->Set( 2 , v8::Number::New(isolate, vec.z));
928 case Dali::Property::VECTOR4:
931 Vector4 vec = value.Get<Vector4>();
932 v8::Local<v8::Array> array= v8::Array::New( isolate, 4 );
933 array->Set( 0 , v8::Number::New(isolate, vec.x));
934 array->Set( 1 , v8::Number::New(isolate, vec.y));
935 array->Set( 2 , v8::Number::New(isolate, vec.z));
936 array->Set( 3 , v8::Number::New(isolate, vec.w));
943 DALI_SCRIPT_EXCEPTION( isolate, "Primitive mismatch \n");
947 object->Set( v8::String::NewFromUtf8( isolate, key.c_str() ), v8Value );
951 void ReadFloatArguments( bool& foundAllArguments, float* data, unsigned int dataSize, const v8::FunctionCallbackInfo< v8::Value >& args, float defaultValue )
953 foundAllArguments = true;
954 unsigned int length = args.Length();
956 if( length < dataSize )
958 foundAllArguments = false;
961 for( unsigned int i = 0; i< dataSize ;i++ )
965 if( args[ i ]->IsNumber() )
967 data[i] = args[i]->NumberValue();
971 data[i] = defaultValue;
972 foundAllArguments = false; // bad argument
977 data[i] = defaultValue; // not enough arguments
983 void ReadIntegerArguments( bool& foundAllArguments, int* data, int dataSize, const v8::FunctionCallbackInfo< v8::Value >& args, int defaultValue )
985 foundAllArguments = true;
986 int length = args.Length();
987 if( length < dataSize )
989 foundAllArguments = false;
992 for( int i = 0; i< dataSize ;i++ )
996 if( args[ i ]->IsInt32() )
998 data[i] = args[i]->Int32Value();
1002 data[i] = defaultValue;
1003 foundAllArguments = false; // bad argument
1008 data[i] = defaultValue; // not enough arguments
1013 } // namespace V8Utils
1015 } // namespace V8Plugin