namespace Xilium.CefGlue { using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using Xilium.CefGlue.Interop; /// /// Class representing a V8 value handle. V8 handles can only be accessed from /// the thread on which they are created. Valid threads for creating a V8 handle /// include the render process main thread (TID_RENDERER) and WebWorker threads. /// A task runner for posting tasks on the associated thread can be retrieved via /// the CefV8Context::GetTaskRunner() method. /// public sealed unsafe partial class CefV8Value { /// /// Create a new CefV8Value object of type undefined. /// public static CefV8Value CreateUndefined() { return CefV8Value.FromNative( cef_v8value_t.create_undefined() ); } /// /// Create a new CefV8Value object of type null. /// public static CefV8Value CreateNull() { return CefV8Value.FromNative( cef_v8value_t.create_null() ); } /// /// Create a new CefV8Value object of type bool. /// public static CefV8Value CreateBool(bool value) { return CefV8Value.FromNative( cef_v8value_t.create_bool(value ? 1 : 0) ); } /// /// Create a new CefV8Value object of type int. /// public static CefV8Value CreateInt(int value) { return CefV8Value.FromNative( cef_v8value_t.create_int(value) ); } /// /// Create a new CefV8Value object of type unsigned int. /// public static CefV8Value CreateUInt(uint value) { return CefV8Value.FromNative( cef_v8value_t.create_uint(value) ); } /// /// Create a new CefV8Value object of type double. /// public static CefV8Value CreateDouble(double value) { return CefV8Value.FromNative( cef_v8value_t.create_double(value) ); } /// /// Create a new CefV8Value object of type Date. This method should only be /// called from within the scope of a CefRenderProcessHandler, CefV8Handler or /// CefV8Accessor callback, or in combination with calling Enter() and Exit() /// on a stored CefV8Context reference. /// public static CefV8Value CreateDate(DateTime value) { var n_value = new cef_time_t(value); return CefV8Value.FromNative( cef_v8value_t.create_date(&n_value) ); } /// /// Create a new CefV8Value object of type string. /// public static CefV8Value CreateString(string value) { fixed (char* value_str = value) { var n_value = new cef_string_t(value_str, value != null ? value.Length : 0); return CefV8Value.FromNative( cef_v8value_t.create_string(&n_value) ); } } /// /// Create a new CefV8Value object of type object with optional accessor and/or /// interceptor. This method should only be called from within the scope of a /// CefRenderProcessHandler, CefV8Handler or CefV8Accessor callback, or in /// combination with calling Enter() and Exit() on a stored CefV8Context /// reference. /// public static CefV8Value CreateObject(CefV8Accessor accessor = null, CefV8Interceptor interceptor = null) { return CefV8Value.FromNative( cef_v8value_t.create_object( accessor != null ? accessor.ToNative() : null, interceptor != null ? interceptor.ToNative() : null ) ); } /// /// Create a new CefV8Value object of type array with the specified |length|. /// If |length| is negative the returned array will have length 0. This method /// should only be called from within the scope of a CefRenderProcessHandler, /// CefV8Handler or CefV8Accessor callback, or in combination with calling /// Enter() and Exit() on a stored CefV8Context reference. /// public static CefV8Value CreateArray(int length) { return CefV8Value.FromNative( cef_v8value_t.create_array(length) ); } /// /// Create a new CefV8Value object of type ArrayBuffer which wraps the provided /// |buffer| of size |length| bytes. The ArrayBuffer is externalized, meaning /// that it does not own |buffer|. The caller is responsible for freeing /// |buffer| when requested via a call to CefV8ArrayBufferReleaseCallback:: /// ReleaseBuffer. This method should only be called from within the scope of a /// CefRenderProcessHandler, CefV8Handler or CefV8Accessor callback, or in /// combination with calling Enter() and Exit() on a stored CefV8Context /// reference. /// public static CefV8Value CreateArrayBuffer(IntPtr buffer, ulong length, CefV8ArrayBufferReleaseCallback releaseCallback) { if (releaseCallback == null) throw new ArgumentNullException(nameof(releaseCallback)); var n_value = cef_v8value_t.create_array_buffer( (void*)buffer, checked((UIntPtr)length), releaseCallback.ToNative() ); return CefV8Value.FromNative(n_value); } /// /// Create a new CefV8Value object of type function. This method should only be /// called from within the scope of a CefRenderProcessHandler, CefV8Handler or /// CefV8Accessor callback, or in combination with calling Enter() and Exit() /// on a stored CefV8Context reference. /// public static CefV8Value CreateFunction(string name, CefV8Handler handler) { fixed (char* name_str = name) { var n_name = new cef_string_t(name_str, name != null ? name.Length : 0); return CefV8Value.FromNative( cef_v8value_t.create_function(&n_name, handler.ToNative()) ); } } /// /// Returns true if the underlying handle is valid and it can be accessed on /// the current thread. Do not call any other methods if this method returns /// false. /// public bool IsValid { get { return cef_v8value_t.is_valid(_self) != 0; } } /// /// True if the value type is undefined. /// public bool IsUndefined { get { return cef_v8value_t.is_undefined(_self) != 0; } } /// /// True if the value type is null. /// public bool IsNull { get { return cef_v8value_t.is_null(_self) != 0; } } /// /// True if the value type is bool. /// public bool IsBool { get { return cef_v8value_t.is_bool(_self) != 0; } } /// /// True if the value type is int. /// public bool IsInt { get { return cef_v8value_t.is_int(_self) != 0; } } /// /// True if the value type is unsigned int. /// public bool IsUInt { get { return cef_v8value_t.is_uint(_self) != 0; } } /// /// True if the value type is double. /// public bool IsDouble { get { return cef_v8value_t.is_double(_self) != 0; } } /// /// True if the value type is Date. /// public bool IsDate { get { return cef_v8value_t.is_date(_self) != 0; } } /// /// True if the value type is string. /// public bool IsString { get { return cef_v8value_t.is_string(_self) != 0; } } /// /// True if the value type is object. /// public bool IsObject { get { return cef_v8value_t.is_object(_self) != 0; } } /// /// True if the value type is array. /// public bool IsArray { get { return cef_v8value_t.is_array(_self) != 0; } } /// /// True if the value type is an ArrayBuffer. /// public bool IsArrayBuffer { get { return cef_v8value_t.is_array_buffer(_self) != 0; } } /// /// True if the value type is function. /// public bool IsFunction { get { return cef_v8value_t.is_function(_self) != 0; } } /// /// Returns true if this object is pointing to the same handle as |that| /// object. /// public bool IsSame(CefV8Value that) { if (that == null) return false; return cef_v8value_t.is_same(_self, that.ToNative()) != 0; } /// /// Return a bool value. /// public bool GetBoolValue() { return cef_v8value_t.get_bool_value(_self) != 0; } /// /// Return an int value. /// public int GetIntValue() { return cef_v8value_t.get_int_value(_self); } /// /// Return an unsigned int value. /// public uint GetUIntValue() { return cef_v8value_t.get_uint_value(_self); } /// /// Return a double value. /// public double GetDoubleValue() { return cef_v8value_t.get_double_value(_self); } /// /// Return a Date value. /// public DateTime GetDateValue() { var value = cef_v8value_t.get_date_value(_self); return cef_time_t.ToDateTime(&value); } /// /// Return a string value. /// public string GetStringValue() { var n_result = cef_v8value_t.get_string_value(_self); return cef_string_userfree.ToString(n_result); } /// /// OBJECT METHODS - These methods are only available on objects. Arrays and /// functions are also objects. String- and integer-based keys can be used /// interchangably with the framework converting between them as necessary. /// Returns true if this is a user created object. /// public bool IsUserCreated { get { return cef_v8value_t.is_user_created(_self) != 0; } } /// /// Returns true if the last method call resulted in an exception. This /// attribute exists only in the scope of the current CEF value object. /// public bool HasException { get { return cef_v8value_t.has_exception(_self) != 0; } } /// /// Returns the exception resulting from the last method call. This attribute /// exists only in the scope of the current CEF value object. /// public CefV8Exception GetException() { return CefV8Exception.FromNativeOrNull( cef_v8value_t.get_exception(_self) ); } /// /// Clears the last exception and returns true on success. /// public bool ClearException() { return cef_v8value_t.clear_exception(_self) != 0; } /// /// Returns true if this object will re-throw future exceptions. This attribute /// exists only in the scope of the current CEF value object. /// public bool WillRethrowExceptions() { return cef_v8value_t.will_rethrow_exceptions(_self) != 0; } /// /// Set whether this object will re-throw future exceptions. By default /// exceptions are not re-thrown. If a exception is re-thrown the current /// context should not be accessed again until after the exception has been /// caught and not re-thrown. Returns true on success. This attribute exists /// only in the scope of the current CEF value object. /// public bool SetRethrowExceptions(bool rethrow) { return cef_v8value_t.set_rethrow_exceptions(_self, rethrow ? 1 : 0) != 0; } /// /// Returns true if the object has a value with the specified identifier. /// public bool HasValue(string key) { fixed (char* key_str = key) { var n_key = new cef_string_t(key_str, key != null ? key.Length : 0); return cef_v8value_t.has_value_bykey(_self, &n_key) != 0; } } /// /// Returns true if the object has a value with the specified identifier. /// public bool HasValue(int index) { return cef_v8value_t.has_value_byindex(_self, index) != 0; } /// /// Deletes the value with the specified identifier and returns true on /// success. Returns false if this method is called incorrectly or an exception /// is thrown. For read-only and don't-delete values this method will return /// true even though deletion failed. /// public bool DeleteValue(string key) { fixed (char* key_str = key) { var n_key = new cef_string_t(key_str, key != null ? key.Length : 0); return cef_v8value_t.delete_value_bykey(_self, &n_key) != 0; } } /// /// Deletes the value with the specified identifier and returns true on /// success. Returns false if this method is called incorrectly, deletion fails /// or an exception is thrown. For read-only and don't-delete values this /// method will return true even though deletion failed. /// public bool DeleteValue(int index) { return cef_v8value_t.delete_value_byindex(_self, index) != 0; } /// /// Returns the value with the specified identifier on success. Returns NULL /// if this method is called incorrectly or an exception is thrown. /// public CefV8Value GetValue(string key) { fixed (char* key_str = key) { var n_key = new cef_string_t(key_str, key != null ? key.Length : 0); return CefV8Value.FromNativeOrNull( cef_v8value_t.get_value_bykey(_self, &n_key) ); } } /// /// Returns the value with the specified identifier on success. Returns NULL /// if this method is called incorrectly or an exception is thrown. /// public CefV8Value GetValue(int index) { return CefV8Value.FromNativeOrNull( cef_v8value_t.get_value_byindex(_self, index) ); } /// /// Associates a value with the specified identifier and returns true on /// success. Returns false if this method is called incorrectly or an exception /// is thrown. For read-only values this method will return true even though /// assignment failed. /// public bool SetValue(string key, CefV8Value value, CefV8PropertyAttribute attribute = CefV8PropertyAttribute.None) { fixed (char* key_str = key) { var n_key = new cef_string_t(key_str, key != null ? key.Length : 0); return cef_v8value_t.set_value_bykey(_self, &n_key, value.ToNative(), attribute) != 0; } } /// /// Associates a value with the specified identifier and returns true on /// success. Returns false if this method is called incorrectly or an exception /// is thrown. For read-only values this method will return true even though /// assignment failed. /// public bool SetValue(int index, CefV8Value value) { return cef_v8value_t.set_value_byindex(_self, index, value.ToNative()) != 0; } /// /// Registers an identifier and returns true on success. Access to the /// identifier will be forwarded to the CefV8Accessor instance passed to /// CefV8Value::CreateObject(). Returns false if this method is called /// incorrectly or an exception is thrown. For read-only values this method /// will return true even though assignment failed. /// public bool SetValue(string key, CefV8AccessControl settings, CefV8PropertyAttribute attribute = CefV8PropertyAttribute.None) { fixed (char* key_str = key) { var n_key = new cef_string_t(key_str, key != null ? key.Length : 0); return cef_v8value_t.set_value_byaccessor(_self, &n_key, settings, attribute) != 0; } } /// /// Read the keys for the object's values into the specified vector. Integer- /// based keys will also be returned as strings. /// public bool TryGetKeys(out string[] keys) { var list = libcef.string_list_alloc(); var result = cef_v8value_t.get_keys(_self, list) != 0; if (result) keys = cef_string_list.ToArray(list); else keys = null; libcef.string_list_free(list); return result; } /// /// Read the keys for the object's values into the specified vector. Integer- /// based keys will also be returned as strings. /// public string[] GetKeys() { string[] keys; if (TryGetKeys(out keys)) return keys; else throw new InvalidOperationException(); } /// /// Sets the user data for this object and returns true on success. Returns /// false if this method is called incorrectly. This method can only be called /// on user created objects. /// public bool SetUserData(CefUserData userData) { return cef_v8value_t.set_user_data(_self, userData != null ? (cef_base_ref_counted_t*)userData.ToNative() : null) != 0; } /// /// Returns the user data, if any, assigned to this object. /// public CefUserData GetUserData() { return CefUserData.FromNativeOrNull( (cef_user_data_t*)cef_v8value_t.get_user_data(_self) ); } /// /// Returns the amount of externally allocated memory registered for the /// object. /// public int GetExternallyAllocatedMemory() { return cef_v8value_t.get_externally_allocated_memory(_self); } /// /// Adjusts the amount of registered external memory for the object. Used to /// give V8 an indication of the amount of externally allocated memory that is /// kept alive by JavaScript objects. V8 uses this information to decide when /// to perform global garbage collection. Each CefV8Value tracks the amount of /// external memory associated with it and automatically decreases the global /// total by the appropriate amount on its destruction. |change_in_bytes| /// specifies the number of bytes to adjust by. This method returns the number /// of bytes associated with the object after the adjustment. This method can /// only be called on user created objects. /// public int AdjustExternallyAllocatedMemory(int changeInBytes) { return cef_v8value_t.adjust_externally_allocated_memory(_self, changeInBytes); } /// /// ARRAY METHODS - These methods are only available on arrays. /// Returns the number of elements in the array. /// public int GetArrayLength() { return cef_v8value_t.get_array_length(_self); } /// /// ARRAY BUFFER METHODS - These methods are only available on ArrayBuffers. /// Returns the ReleaseCallback object associated with the ArrayBuffer or NULL /// if the ArrayBuffer was not created with CreateArrayBuffer. /// public CefV8ArrayBufferReleaseCallback GetArrayBufferReleaseCallback() { var n_releaseCallback = cef_v8value_t.get_array_buffer_release_callback(_self); return CefV8ArrayBufferReleaseCallback.FromNativeOrNull(n_releaseCallback); } /// /// Prevent the ArrayBuffer from using it's memory block by setting the length /// to zero. This operation cannot be undone. If the ArrayBuffer was created /// with CreateArrayBuffer then CefV8ArrayBufferReleaseCallback::ReleaseBuffer /// will be called to release the underlying buffer. /// public bool NeuterArrayBuffer() { return cef_v8value_t.neuter_array_buffer(_self) != 0; } /// /// FUNCTION METHODS - These methods are only available on functions. /// Returns the function name. /// public string GetFunctionName() { var n_result = cef_v8value_t.get_function_name(_self); return cef_string_userfree.ToString(n_result); } /// /// Returns the function handler or NULL if not a CEF-created function. /// public CefV8Handler GetFunctionHandler() { return CefV8Handler.FromNativeOrNull( cef_v8value_t.get_function_handler(_self) ); } /// /// Execute the function using the current V8 context. This method should only /// be called from within the scope of a CefV8Handler or CefV8Accessor /// callback, or in combination with calling Enter() and Exit() on a stored /// CefV8Context reference. |object| is the receiver ('this' object) of the /// function. If |object| is empty the current context's global object will be /// used. |arguments| is the list of arguments that will be passed to the /// function. Returns the function return value on success. Returns NULL if /// this method is called incorrectly or an exception is thrown. /// public CefV8Value ExecuteFunction(CefV8Value obj, CefV8Value[] arguments) { var n_arguments = CreateArguments(arguments); cef_v8value_t* n_retval; fixed (cef_v8value_t** n_arguments_ptr = n_arguments) { n_retval = cef_v8value_t.execute_function( _self, obj != null ? obj.ToNative() : null, n_arguments != null ? (UIntPtr)n_arguments.Length : UIntPtr.Zero, n_arguments_ptr ); } return CefV8Value.FromNativeOrNull(n_retval); } /// /// Execute the function using the specified V8 context. |object| is the /// receiver ('this' object) of the function. If |object| is empty the /// specified context's global object will be used. |arguments| is the list of /// arguments that will be passed to the function. Returns the function return /// value on success. Returns NULL if this method is called incorrectly or an /// exception is thrown. /// public CefV8Value ExecuteFunctionWithContext(CefV8Context context, CefV8Value obj, CefV8Value[] arguments) { var n_arguments = CreateArguments(arguments); cef_v8value_t* n_retval; fixed (cef_v8value_t** n_arguments_ptr = n_arguments) { n_retval = cef_v8value_t.execute_function_with_context( _self, context.ToNative(), obj != null ? obj.ToNative() : null, n_arguments != null ? (UIntPtr)n_arguments.Length : UIntPtr.Zero, n_arguments_ptr ); } return CefV8Value.FromNativeOrNull(n_retval); } private static cef_v8value_t*[] CreateArguments(CefV8Value[] arguments) { if (arguments == null) return null; var length = arguments.Length; if (length == 0) return null; var result = new cef_v8value_t*[arguments.Length]; for (var i = 0; i < length; i++) { result[i] = arguments[i].ToNative(); } return result; } } }