X Tutup
// Copyright (c) 2013 CEF Python, see the Authors file. // All rights reserved. Licensed under BSD 3-clause license. // Project website: https://github.com/cztomczak/cefpython // CefListValue->SetXxxx() functions need first param to be be cast // to (int) because GetSize() returns size_t and generates a warning // when compiling on VS2008 for x64 platform. Issue reported here: // https://github.com/cztomczak/cefpython/issues/165 #include "v8utils.h" #include "javascript_callback.h" #include "include/base/cef_logging.h" #include "cefpython_app.h" #include // ---------------------------------------------------------------------------- // V8 values to CEF values. // ---------------------------------------------------------------------------- CefRefPtr V8ValueListToCefListValue( const CefV8ValueList& v8List) { // typedef std::vector > CefV8ValueList; CefRefPtr listValue = CefListValue::Create(); for (CefV8ValueList::const_iterator it = v8List.begin(); it != v8List.end(); \ ++it) { CefRefPtr v8Value = *it; V8ValueAppendToCefListValue(v8Value, listValue); } return listValue; } void V8ValueAppendToCefListValue(CefRefPtr v8Value, CefRefPtr listValue, int nestingLevel) { if (!v8Value->IsValid()) { LOG(ERROR) << "[Renderer process] V8ValueAppendToCefListValue():" " IsValid() failed"; return; } if (nestingLevel > 8) { LOG(ERROR) << "[Renderer process] V8ValueAppendToCefListValue():" " 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 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 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 context = \ CefV8Context::GetCurrentContext(); CefRefPtr 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()); LOG(ERROR) << "[Renderer process] V8ValueAppendToCefListValue():" " not in V8 context"; return; } } 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()); LOG(ERROR) << "[Renderer process] V8ValueAppendToCefListValue():" " unknown V8 type"; } } CefRefPtr V8ObjectToCefDictionaryValue( CefRefPtr v8Object, int nestingLevel) { if (!v8Object->IsValid()) { LOG(ERROR) << "[Renderer process] V8ObjectToCefDictionaryValue():" " IsValid() failed"; return CefDictionaryValue::Create(); } if (nestingLevel > 8) { LOG(ERROR) << "[Renderer process] V8ObjectToCefDictionaryValue():" " max nesting level (8) exceeded"; return CefDictionaryValue::Create(); } if (!v8Object->IsObject()) { LOG(ERROR) << "[Renderer process] V8ObjectToCefDictionaryValue():" " IsObject() failed"; return CefDictionaryValue::Create(); } CefRefPtr ret = CefDictionaryValue::Create(); std::vector keys; if (!v8Object->GetKeys(keys)) { LOG(ERROR) << "[Renderer process] V8ObjectToCefDictionaryValue():" " GetKeys() failed"; return ret; } for (std::vector::iterator it = keys.begin(); \ it != keys.end(); ++it) { CefString key = *it; CefRefPtr v8Value = v8Object->GetValue(key); if (v8Value->IsUndefined() || v8Value->IsNull()) { ret->SetNull(key); } else if (v8Value->IsBool()) { ret->SetBool(key, v8Value->GetBoolValue()); } else if (v8Value->IsInt()) { ret->SetInt(key, v8Value->GetIntValue()); } else if (v8Value->IsUInt()) { uint32 uint32_value = v8Value->GetUIntValue(); CefRefPtr binaryValue = CefBinaryValue::Create( &uint32_value, sizeof(uint32_value)); ret->SetBinary(key, binaryValue); } else if (v8Value->IsDouble()) { ret->SetDouble(key, 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. ret->SetNull(key); } else if (v8Value->IsString()) { ret->SetString(key, v8Value->GetStringValue()); } else if (v8Value->IsArray()) { // Check for IsArray() must happen before the IsObject() check. int length = v8Value->GetArrayLength(); CefRefPtr newListValue = CefListValue::Create(); for (int i = 0; i < length; ++i) { V8ValueAppendToCefListValue(v8Value->GetValue(i), newListValue, nestingLevel + 1); } ret->SetList(key, newListValue); } else if (v8Value->IsFunction()) { // Check for IsFunction() must happen before the IsObject() check. if (CefV8Context::InContext()) { CefRefPtr context = \ CefV8Context::GetCurrentContext(); CefRefPtr frame = context->GetFrame(); std::string strCallbackId = PutJavascriptCallback( frame, v8Value); /* strCallbackId = '####cefpython####' \ '{"what"=>"javascript-callback", ..}' */ ret->SetString(key, strCallbackId); } else { ret->SetNull(key); LOG(ERROR) << "[Renderer process]" " V8ObjectToCefDictionaryValue():" " not in V8 context"; } } else if (v8Value->IsObject()) { // Check for IsObject() must happen after the IsArray() // and IsFunction() checks. ret->SetDictionary(key, V8ObjectToCefDictionaryValue(v8Value, nestingLevel + 1)); } else { ret->SetNull(key); LOG(ERROR) << "[Renderer process] V8ObjectToCefDictionaryValue():" " unknown V8 type"; } } return ret; } // ---------------------------------------------------------------------------- // CEF values to V8 values. // ---------------------------------------------------------------------------- // TODO: send callbackId using CefBinaryNamedValue, see: // http://www.magpcss.org/ceforum/viewtopic.php?f=6&t=10881 struct PythonCallback { int callbackId; char uniqueCefBinaryValueSize[16]; }; template inline std::string AnyToString(const T& value) { std::ostringstream oss; oss << value; return oss.str(); } CefV8ValueList CefListValueToCefV8ValueList( CefRefPtr listValue) { // CefV8ValueList = typedef std::vector > CefV8ValueList v8ValueVector; CefRefPtr v8List = CefListValueToV8Value(listValue); int v8ListLength = v8List->GetArrayLength(); for (int i = 0; i < v8ListLength; ++i) { v8ValueVector.push_back(v8List->GetValue(i)); } return v8ValueVector; } CefRefPtr CefListValueToV8Value( CefRefPtr listValue, int nestingLevel) { if (!listValue->IsValid()) { LOG(ERROR) << "[Renderer process] CefListValueToV8Value():" " CefDictionaryValue is invalid"; return CefV8Value::CreateNull(); } if (nestingLevel > 8) { LOG(ERROR) << "[Renderer process] CefListValueToV8Value():" " max nesting level (8) exceeded"; return CefV8Value::CreateNull(); } int listSize = (int)listValue->GetSize(); CefRefPtr ret = CefV8Value::CreateArray(listSize); CefRefPtr binaryValue; PythonCallback pyCallback; CefRefPtr v8FunctionHandler; for (int key = 0; key < listSize; ++key) { cef_value_type_t valueType = listValue->GetType(key); bool success; std::string callbackName = "python_callback_"; if (valueType == VTYPE_NULL) { success = ret->SetValue(key, CefV8Value::CreateNull()); } else if (valueType == VTYPE_BOOL) { success = ret->SetValue(key, CefV8Value::CreateBool(listValue->GetBool(key))); } else if (valueType == VTYPE_INT) { success = ret->SetValue(key, CefV8Value::CreateInt(listValue->GetInt(key))); } else if (valueType == VTYPE_DOUBLE) { success = ret->SetValue(key, CefV8Value::CreateDouble(listValue->GetDouble(key))); } else if (valueType == VTYPE_STRING) { success = ret->SetValue(key, CefV8Value::CreateString(listValue->GetString(key))); } else if (valueType == VTYPE_BINARY) { binaryValue = listValue->GetBinary(key); if (binaryValue->GetSize() == sizeof(pyCallback)) { binaryValue->GetData(&pyCallback, sizeof(pyCallback), 0); v8FunctionHandler = new V8FunctionHandler( NULL, pyCallback.callbackId); // You must provide a function name to // CefV8Value::CreateFunction(), otherwise it fails. callbackName.append(AnyToString(pyCallback.callbackId)); success = ret->SetValue(key, CefV8Value::CreateFunction( callbackName, v8FunctionHandler)); } else { LOG(ERROR) << "[Renderer process] CefListValueToV8Value():" " unknown binary value, setting value to null"; success = ret->SetValue(key, CefV8Value::CreateNull()); } } else if (valueType == VTYPE_DICTIONARY) { success = ret->SetValue(key, CefDictionaryValueToV8Value( listValue->GetDictionary(key), nestingLevel + 1)); } else if (valueType == VTYPE_LIST) { success = ret->SetValue(key, CefListValueToV8Value( listValue->GetList(key), nestingLevel + 1)); } else { LOG(ERROR) << "[Renderer process] CefListValueToV8Value():" " unknown type, setting value to null"; success = ret->SetValue(key, CefV8Value::CreateNull()); } if (!success) { LOG(ERROR) << "[Renderer process] CefListValueToV8Value():" " ret->SetValue() failed"; } } return ret; } CefRefPtr CefDictionaryValueToV8Value( CefRefPtr dictValue, int nestingLevel) { if (!dictValue->IsValid()) { LOG(ERROR) << "[Renderer process] CefDictionaryValueToV8Value():" " CefDictionaryValue is invalid"; return CefV8Value::CreateNull(); } if (nestingLevel > 8) { LOG(ERROR) << "[Renderer process] CefDictionaryValueToV8Value():" " max nesting level (8) exceeded"; return CefV8Value::CreateNull(); } std::vector keys; if (!dictValue->GetKeys(keys)) { LOG(ERROR) << "[Renderer process] CefDictionaryValueToV8Value():" " dictValue->GetKeys() failed"; return CefV8Value::CreateNull(); } CefRefPtr ret = CefV8Value::CreateObject(NULL, NULL); CefRefPtr binaryValue; PythonCallback pyCallback; CefRefPtr v8FunctionHandler; for (std::vector::iterator it = keys.begin(); \ it != keys.end(); ++it) { CefString key = *it; cef_value_type_t valueType = dictValue->GetType(key); bool success; std::string callbackName = "python_callback_"; if (valueType == VTYPE_NULL) { success = ret->SetValue(key, CefV8Value::CreateNull(), V8_PROPERTY_ATTRIBUTE_NONE); } else if (valueType == VTYPE_BOOL) { success = ret->SetValue(key, CefV8Value::CreateBool(dictValue->GetBool(key)), V8_PROPERTY_ATTRIBUTE_NONE); } else if (valueType == VTYPE_INT) { success = ret->SetValue(key, CefV8Value::CreateInt(dictValue->GetInt(key)), V8_PROPERTY_ATTRIBUTE_NONE); } else if (valueType == VTYPE_DOUBLE) { success = ret->SetValue(key, CefV8Value::CreateDouble(dictValue->GetDouble(key)), V8_PROPERTY_ATTRIBUTE_NONE); } else if (valueType == VTYPE_STRING) { success = ret->SetValue(key, CefV8Value::CreateString(dictValue->GetString(key)), V8_PROPERTY_ATTRIBUTE_NONE); } else if (valueType == VTYPE_BINARY) { binaryValue = dictValue->GetBinary(key); if (binaryValue->GetSize() == sizeof(pyCallback)) { binaryValue->GetData(&pyCallback, sizeof(pyCallback), 0); v8FunctionHandler = new V8FunctionHandler( NULL, pyCallback.callbackId); // You must provide a function name to // CefV8Value::CreateFunction(), otherwise it fails. callbackName.append(AnyToString(pyCallback.callbackId)); success = ret->SetValue(key, CefV8Value::CreateFunction( callbackName, v8FunctionHandler), V8_PROPERTY_ATTRIBUTE_NONE); } else { LOG(ERROR) << "[Renderer process] CefListValueToV8Value():" " unknown binary value, setting value to null"; success = ret->SetValue(key, CefV8Value::CreateNull(), V8_PROPERTY_ATTRIBUTE_NONE); } } else if (valueType == VTYPE_DICTIONARY) { success = ret->SetValue(key, CefDictionaryValueToV8Value( dictValue->GetDictionary(key), nestingLevel + 1), V8_PROPERTY_ATTRIBUTE_NONE); } else if (valueType == VTYPE_LIST) { success = ret->SetValue(key, CefListValueToV8Value( dictValue->GetList(key), nestingLevel + 1), V8_PROPERTY_ATTRIBUTE_NONE); } else { LOG(ERROR) << "[Renderer process] CefDictionaryValueToV8Value():" " unknown type, setting value to null"; success = ret->SetValue(key, CefV8Value::CreateNull(), V8_PROPERTY_ATTRIBUTE_NONE); } if (!success) { LOG(ERROR) << "[Renderer process] CefDictionaryValueToV8Value():" " ret->SetValue() failed"; } } return ret; }
X Tutup