CefRefPtr<CefListValue> FUnrealCEFSubProcessRemoteScripting::V8ArrayToCef(CefRefPtr<CefV8Value> Array) { CefRefPtr<CefListValue> Result = CefListValue::Create(); if (Array->IsArray()) { for (int I = 0; I < Array->GetArrayLength(); ++I) { V8ToCef(Result, Array, I, Array->GetValue(I)); } } return Result; }
// Transfer a V8 array to a List. void SetList(CefRefPtr<CefV8Value> source, CefRefPtr<CefListValue> target) { ASSERT(source->IsArray()); int arg_length = source->GetArrayLength(); if (arg_length == 0) return; // Start with null types in all spaces. target->SetSize(arg_length); for (int i = 0; i < arg_length; ++i) SetListValue(target, i, source->GetValue(i)); }
bool FUnrealCEFSubProcessRemoteObject::ExecuteMethod(const CefString& MethodName, CefRefPtr<CefV8Value> Object, const CefV8ValueList& Arguments, CefRefPtr<CefV8Value>& Retval, CefString& InException) { CefRefPtr<CefV8Context> Context = CefV8Context::GetCurrentContext(); CefRefPtr<CefV8Exception> Exception; CefRefPtr<CefV8Value> PromiseObjects; // Run JS code that creates and unwraps a Promise object if (!Context->Eval( "(function() " \ "{ " " var Accept, Reject, PromiseObject;" \ " PromiseObject = new Promise(function(InAccept, InReject) " \ " {" " Accept = InAccept;" \ " Reject = InReject;" \ " });" \ " return [PromiseObject, Accept, Reject];" \ "})()" , PromiseObjects, Exception)) { InException = Exception->GetMessage(); return false; } if (!(PromiseObjects.get() && PromiseObjects->IsArray() && PromiseObjects->GetArrayLength() == 3)) { return false; } Retval = PromiseObjects->GetValue(0); CefRefPtr<CefV8Value> Accept = PromiseObjects->GetValue(1); CefRefPtr<CefV8Value> Reject = PromiseObjects->GetValue(2); check(Retval->IsObject()); check(Accept->IsFunction()); check(Reject->IsFunction()); FGuid CallbackGuid = RemoteScripting->CallbackRegistry.FindOrAdd(Context, Retval, Accept, Reject, true); CefRefPtr<CefProcessMessage> Message = CefProcessMessage::Create("UE::ExecuteUObjectMethod"); CefRefPtr<CefListValue> MessageArguments = Message->GetArgumentList(); MessageArguments->SetString(0, CefString(*ObjectId.ToString(EGuidFormats::Digits))); MessageArguments->SetString(1, MethodName); MessageArguments->SetString(2, CefString(*CallbackGuid.ToString(EGuidFormats::Digits))); MessageArguments->SetList(3, RemoteScripting->V8ArrayToCef(Arguments)); Browser->SendProcessMessage(PID_BROWSER, Message); return true; }
// Simple function for formatted output of a V8 value. void PrintValue(CefRefPtr<CefV8Value> value, std::stringstream &stream, int indent) { std::stringstream indent_stream; for(int i = 0; i < indent; ++i) indent_stream << " "; std::string indent_str = indent_stream.str(); if(value->IsUndefined()) stream << "(undefined)"; else if(value->IsNull()) stream << "(null)"; else if(value->IsBool()) stream << "(bool) " << (value->GetBoolValue() ? "true" : "false"); else if(value->IsInt()) stream << "(int) " << value->GetIntValue(); else if(value->IsDouble()) stream << "(double) " << value->GetDoubleValue(); else if(value->IsString()) stream << "(string) " << std::string(value->GetStringValue()); else if(value->IsFunction()) stream << "(function) " << std::string(value->GetFunctionName()); else if(value->IsArray()) { stream << "(array) ["; int len = value->GetArrayLength(); for(int i = 0; i < len; ++i) { stream << "\n " << indent_str.c_str() << i << " = "; PrintValue(value->GetValue(i), stream, indent+1); } stream << "\n" << indent_str.c_str() << "]"; } else if(value->IsObject()) { stream << "(object) ["; std::vector<CefString> keys; if(value->GetKeys(keys)) { for(size_t i = 0; i < keys.size(); ++i) { stream << "\n " << indent_str.c_str() << keys[i].c_str() << " = "; PrintValue(value->GetValue(keys[i]), stream, indent+1); } } stream << "\n" << indent_str.c_str() << "]"; } }
CefRefPtr<CefV8Value> IPC_Container::GetAttributesV8Value( CefRefPtr<CefV8Context> context, std::string array_variable, int obj_index_in_array, ContainerAttribute attr) { CefRefPtr<CefV8Value> containerObjArray = context->GetGlobal()->GetValue(array_variable); if (obj_index_in_array < containerObjArray->GetArrayLength()) { CefRefPtr<CefV8Value> containerObj = containerObjArray->GetValue(obj_index_in_array); // Get objects attribute by attribute's name return containerObj->GetValue(attr.GetName()); } else { // DLOG(WARNING) << "WARNING: V8ArrayLength not as big as expected!"; // TODO: Handle NULL in following steps... return CefV8Value::CreateNull(); } }
void V8ValueAppendToCefListValue(CefRefPtr<CefV8Value> v8Value, CefRefPtr<CefListValue> listValue, int nestingLevel) { if (!v8Value->IsValid()) { DebugLog("V8ValueAppendToCefListValue(): IsValid() FAILED"); return; } if (nestingLevel > 8) { DebugLog("V8ValueAppendToCefListValue(): WARNING: max nesting level (8) " \ "exceeded"); return; } if (v8Value->IsUndefined() || v8Value->IsNull()) { listValue->SetNull((int)listValue->GetSize()); } else if (v8Value->IsBool()) { listValue->SetBool((int)listValue->GetSize(), v8Value->GetBoolValue()); } else if (v8Value->IsInt()) { listValue->SetInt((int)listValue->GetSize(), v8Value->GetIntValue()); } else if (v8Value->IsUInt()) { uint32 uint32_value = v8Value->GetUIntValue(); CefRefPtr<CefBinaryValue> binaryValue = CefBinaryValue::Create( &uint32_value, sizeof(uint32_value)); listValue->SetBinary((int)listValue->GetSize(), binaryValue); } else if (v8Value->IsDouble()) { listValue->SetDouble((int)listValue->GetSize(), v8Value->GetDoubleValue()); } else if (v8Value->IsDate()) { // TODO: in time_utils.pyx there are already functions for // converting cef_time_t to python DateTime, we could easily // add a new function for converting the python DateTime to // string and then to CefString and expose the function using // the "public" keyword. But how do we get the cef_time_t // structure from the CefTime class? GetDateValue() returns // CefTime class. listValue->SetNull((int)listValue->GetSize()); } else if (v8Value->IsString()) { listValue->SetString((int)listValue->GetSize(), v8Value->GetStringValue()); } else if (v8Value->IsArray()) { // Check for IsArray() must happen before the IsObject() check. int length = v8Value->GetArrayLength(); CefRefPtr<CefListValue> newListValue = CefListValue::Create(); for (int i = 0; i < length; ++i) { V8ValueAppendToCefListValue(v8Value->GetValue(i), newListValue, nestingLevel + 1); } listValue->SetList((int)listValue->GetSize(), newListValue); } else if (v8Value->IsFunction()) { // Check for IsFunction() must happen before the IsObject() check. if (CefV8Context::InContext()) { CefRefPtr<CefV8Context> context = \ CefV8Context::GetCurrentContext(); CefRefPtr<CefFrame> frame = context->GetFrame(); std::string strCallbackId = PutJavascriptCallback(frame, v8Value); /* strCallbackId = '####cefpython####' \ '{"what"=>"javascript-callback", ..}' */ listValue->SetString((int)listValue->GetSize(), strCallbackId); } else { listValue->SetNull((int)listValue->GetSize()); DebugLog("V8ValueAppendToCefListValue() FAILED: not in V8 context" " , FATAL ERROR!"); } } else if (v8Value->IsObject()) { // Check for IsObject() must happen after the IsArray() // and IsFunction() checks. listValue->SetDictionary((int)listValue->GetSize(), V8ObjectToCefDictionaryValue(v8Value, nestingLevel + 1)); } else { listValue->SetNull((int)listValue->GetSize()); DebugLog("V8ValueAppendToCefListValue() FAILED: unknown V8 type"); } }
virtual bool Execute(const CefString& InName, CefRefPtr<CefV8Value> InObject, const CefV8ValueList& InArguments, CefRefPtr<CefV8Value>& OutRetval, CefString& OutException) { bool Handled = false; bool ValidAPI = true; if (InName == "TriggerEvent") { // dispatch hook to the browser process for execution on the game thread if ((InArguments.size() == 1) && InArguments[0]->IsArray()) { CefRefPtr<CefV8Value> ArgumentArray = InArguments[0]; if (ArgumentArray->GetArrayLength() > 0) { CefRefPtr<CefBrowser> Browser = CefV8Context::GetCurrentContext()->GetBrowser(); ASSERT(Browser.get()); CefString HookName = ArgumentArray->GetValue(0)->GetStringValue(); if (!HookName.empty()) { CefRefPtr<CefProcessMessage> Message = CefProcessMessage::Create(HookName); // translate remaining args. if ((ArgumentArray->GetArrayLength() > 1) && ArgumentArray->GetValue(1)->IsArray()) { CefRefPtr<CefV8Value> InParameters = ArgumentArray->GetValue(1); const int NumParameters = InParameters->GetArrayLength(); CefRefPtr<CefListValue> OutParameters = Message->GetArgumentList(); OutParameters->SetSize(NumParameters); for (int i = 0; i < (int)NumParameters; ++i) { V8ValueToListItem_RenderThread(InParameters->GetValue(i), OutParameters, i); } } Browser->SendProcessMessage(PID_BROWSER, Message); Handled = true; } } } } else if (InName == "SetHook") { if ((InArguments.size() == 2) && (InArguments[0]->IsString()) && (InArguments[1]->IsFunction())) { CefString HookName = InArguments[0]->GetStringValue().ToString(); CefRefPtr<CefV8Context> Context = CefV8Context::GetCurrentContext(); App->SetJSHook(HookName, Context->GetBrowser()->GetIdentifier(), Context, InArguments[1]); Handled = true; } } else if (InName == "RemoveHook") { if ((InArguments.size() == 1) && InArguments[0]->IsString()) { CefRefPtr<CefV8Context> Context = CefV8Context::GetCurrentContext(); App->RemoveJSHook(InArguments[0]->GetStringValue(), Context->GetBrowser()->GetIdentifier()); Handled = true; } } else { ValidAPI = false; OutException = std::string("Unrecognized JSHook API Call: '") + InName.ToString() + std::string("'"); } if (!Handled && ValidAPI) { OutException = std::string("Invalid Arguments Passed To '") + InName.ToString() + std::string("'"); } return Handled; }