X Tutup
# Copyright (c) 2012-2014 The CEF Python authors. All rights reserved. # License: New BSD License. # Website: http://code.google.com/p/cefpython/ # CefV8 Objects, Arrays and Functions can be created or modified only # inside V8 context, you need to call CefV8Context::Enter() and # CefV8Context::Exit(), see: # http://code.google.com/p/chromiumembedded/issues/detail?id=203 cdef list CefV8StackTraceToPython(CefRefPtr[CefV8StackTrace] cefTrace): cdef int frameNumber cdef int frameCount = cefTrace.get().GetFrameCount() cdef CefRefPtr[CefV8StackFrame] cefFrame cdef CefV8StackFrame* framePtr cdef list pyTrace = [] for frameNumber in range(0, frameCount): cefFrame = cefTrace.get().GetFrame(frameNumber) framePtr = cefFrame.get() pyFrame = {} pyFrame["script"] = CefToPyString(framePtr.GetScriptName()) pyFrame["scriptOrSourceUrl"] = CefToPyString( framePtr.GetScriptNameOrSourceURL()) pyFrame["function"] = CefToPyString(framePtr.GetFunctionName()) pyFrame["line"] = framePtr.GetLineNumber() pyFrame["column"] = framePtr.GetColumn() pyFrame["isEval"] = framePtr.IsEval() pyFrame["isConstructor"] = framePtr.IsConstructor() pyTrace.append(pyFrame) return pyTrace cpdef list GetJavascriptStackTrace(int frameLimit=100): assert IsThread(TID_UI), ( "cefpython.GetJavascriptStackTrace() may only be called on the UI thread") cdef CefRefPtr[CefV8StackTrace] cefTrace = ( cef_v8_stack_trace.GetCurrent(frameLimit)) return CefV8StackTraceToPython(cefTrace) cpdef str FormatJavascriptStackTrace(list stackTrace): cdef str formatted = "" cdef dict frame for frameNumber, frame in enumerate(stackTrace): formatted += "\t[%s] %s() in %s on line %s (col:%s)\n" % ( frameNumber, frame["function"], frame["scriptOrSourceUrl"], frame["line"], frame["column"]) return formatted cdef object V8ToPyValue( CefRefPtr[CefV8Value] v8Value, CefRefPtr[CefV8Context] v8Context, int nestingLevel=0): # With nestingLevel > 10 we get system exceptions. if nestingLevel > 8: raise Exception("V8ToPyValue() failed: data passed from Javascript to " "Python has more than 8 levels of nesting, this is probably an infinite " "recursion, stopping.") cdef CefV8Value* v8ValuePtr = v8Value.get() cdef CefString cefString cdef CefString cefFuncName cdef cpp_vector[CefString] keys cdef cpp_vector[CefString].iterator iterator cdef list pyArray cdef int callbackId cdef dict pyDict # A test against IsArray should be done before IsObject(). if v8ValuePtr.IsArray(): pyArray = [] for key in range(0, v8ValuePtr.GetArrayLength()): pyArray.append(V8ToPyValue( v8ValuePtr.GetValue(int(key)), v8Context, nestingLevel+1)) return pyArray elif v8ValuePtr.IsBool(): return v8ValuePtr.GetBoolValue() elif v8ValuePtr.IsDate(): # TODO: convert it to string with no error. raise Exception("V8ToPyValue() failed: Date object is not supported, " "you are not allowed to pass it from Javascript to Python.") elif v8ValuePtr.IsInt(): # A check against IsInt() must be done before IsDouble(), as any js integer # returns true when calling IsDouble(). return v8ValuePtr.GetIntValue() elif v8ValuePtr.IsUInt(): return v8ValuePtr.GetUIntValue() elif v8ValuePtr.IsDouble(): return v8ValuePtr.GetDoubleValue() elif v8ValuePtr.IsFunction(): callbackId = PutV8JavascriptCallback(v8Value, v8Context) return JavascriptCallback(callbackId) elif v8ValuePtr.IsNull(): return None elif v8ValuePtr.IsObject(): # A test against IsObject() should be done after IsArray(). # Remember about increasing the nestingLevel. v8ValuePtr.GetKeys(keys) iterator = keys.begin() pyDict = {} while iterator != keys.end(): cefString = deref(iterator) key = CefToPyString(cefString) value = V8ToPyValue( v8ValuePtr.GetValue(cefString), v8Context, nestingLevel+1) pyDict[key] = value preinc(iterator) return pyDict elif v8ValuePtr.IsString(): return CefToPyString(v8ValuePtr.GetStringValue()) elif v8ValuePtr.IsUndefined(): return None else: raise Exception("V8ToPyValue() failed: unknown type of CefV8Value.") # Any function calling PyToV8Value must be inside that v8Context, # check current context and call Enter if required otherwise exception is # thrown while trying to create an array, object or function. cdef CefRefPtr[CefV8Value] PyToV8Value( object pyValue, CefRefPtr[CefV8Context] v8Context, int nestingLevel=0) except *: # With nestingLevel > 10 we get system exceptions. if nestingLevel > 8: raise Exception("PyToV8Value() failed: data passed from Python " "to Javascript has more than 8 levels of nesting, this is probably " "an infinite recursion, stopping.") cdef cpp_bool sameContext if g_debug: sameContext = v8Context.get().IsSame(cef_v8_static.GetCurrentContext()) if not sameContext: raise Exception("PyToV8Value() called in wrong v8 context") cdef CefString cefString cdef CefRefPtr[CefV8Value] v8Value cdef CefString cefFuncName cdef type pyValueType = type(pyValue) if pyValueType == tuple: pyValue = list(pyValue) # Check type again, as code above may have changed it. pyValueType = type(pyValue) cdef int index cdef object value cdef CefRefPtr[V8FunctionHandler] v8FunctionHandler cdef CefRefPtr[CefV8Handler] v8Handler cdef int callbackId cdef object key if pyValueType == list: v8Value = cef_v8_static.CreateArray(len(pyValue)) for index,value in enumerate(pyValue): v8Value.get().SetValue( index, PyToV8Value(value, v8Context, nestingLevel+1)) return v8Value elif pyValueType == bool: return cef_v8_static.CreateBool(bool(pyValue)) elif pyValueType == int: return cef_v8_static.CreateInt(int(pyValue)) elif pyValueType == long: # Int32 range is -2147483648..2147483647, we've increased the # minimum size by one as Cython was throwing a warning: # "unary minus operator applied to unsigned type, result still # unsigned". if pyValue <= 2147483647 and pyValue >= -2147483647: return cef_v8_static.CreateInt(int(pyValue)) else: PyToCefString(str(pyValue), cefString) return cef_v8_static.CreateString(cefString) elif pyValueType == float: return cef_v8_static.CreateDouble(float(pyValue)) elif pyValueType == types.FunctionType or pyValueType == types.MethodType: v8FunctionHandler = new V8FunctionHandler() v8FunctionHandler.get().SetContext(v8Context) v8Handler = v8FunctionHandler.get() PyToCefString(pyValue.__name__, cefFuncName) # V8PythonCallback. v8Value = cef_v8_static.CreateFunction(cefFuncName, v8Handler) callbackId = PutPythonCallback(pyValue) v8FunctionHandler.get().SetCallback_RemovePythonCallback( RemovePythonCallback) v8FunctionHandler.get().SetPythonCallbackID(callbackId) return v8Value elif pyValueType == type(None): return cef_v8_static.CreateNull() elif pyValueType == dict: v8Value = cef_v8_static.CreateObject(NULL) for key, value in pyValue.items(): # A dict may have an int key, a string key or even a tuple key: # {0: 12, '0': 12, (0, 1): 123} # Remember about increasing nestingLevel. PyToCefString(str(key), cefString) v8Value.get().SetValue( cefString, PyToV8Value(value, v8Context, nestingLevel+1), V8_PROPERTY_ATTRIBUTE_NONE) return v8Value elif pyValueType == bytes or pyValueType == str \ or (PY_MAJOR_VERSION < 3 and pyValueType == unicode): # The unicode type is not defined in Python 3. PyToCefString(pyValue, cefString) return cef_v8_static.CreateString(cefString) elif pyValueType == type: PyToCefString(str(pyValue), cefString) return cef_v8_static.CreateString(cefString) else: raise Exception("PyToV8Value() failed: an unsupported python type " "was passed from python to javascript: %s, value: %s" % (pyValueType.__name__, pyValue))
X Tutup