From 45b333fa449af76f19d016702bd638fd47e03445 Mon Sep 17 00:00:00 2001 From: Christopher Cifra Date: Tue, 10 Apr 2018 15:37:33 -0400 Subject: [PATCH] Add support for V8 ArrayBuffers (issue #244) --- cef_paths.gypi | 6 +- include/capi/cef_v8_capi.h | 60 ++++++- include/cef_v8.h | 56 ++++++ libcef/renderer/v8_impl.cc | 161 ++++++++++++++++++ libcef/renderer/v8_impl.h | 4 + .../v8array_buffer_release_callback_cpptoc.cc | 70 ++++++++ .../v8array_buffer_release_callback_cpptoc.h | 37 ++++ libcef_dll/cpptoc/v8value_cpptoc.cc | 75 +++++++- .../v8array_buffer_release_callback_ctocpp.cc | 63 +++++++ .../v8array_buffer_release_callback_ctocpp.h | 40 +++++ libcef_dll/ctocpp/v8value_ctocpp.cc | 71 +++++++- libcef_dll/ctocpp/v8value_ctocpp.h | 6 +- libcef_dll/libcef_dll.cc | 5 +- libcef_dll/wrapper/libcef_dll_wrapper.cc | 5 +- libcef_dll/wrapper_types.h | 3 +- tests/ceftests/v8_unittest.cc | 121 +++++++++++++ 16 files changed, 775 insertions(+), 8 deletions(-) create mode 100644 libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc create mode 100644 libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h create mode 100644 libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc create mode 100644 libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h diff --git a/cef_paths.gypi b/cef_paths.gypi index 710b8ca47..e261a771d 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -8,7 +8,7 @@ # by hand. See the translator.README.txt file in the tools directory for # more information. # -# $hash=bede6f61d0f5b45669b8e924144e4200c41f869b$ +# $hash=67bc21133e37f5361a39f25dcfe004616d467dbc$ # { @@ -432,6 +432,8 @@ 'libcef_dll/ctocpp/urlrequest_client_ctocpp.h', 'libcef_dll/ctocpp/v8accessor_ctocpp.cc', 'libcef_dll/ctocpp/v8accessor_ctocpp.h', + 'libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc', + 'libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h', 'libcef_dll/cpptoc/v8context_cpptoc.cc', 'libcef_dll/cpptoc/v8context_cpptoc.h', 'libcef_dll/cpptoc/v8exception_cpptoc.cc', @@ -712,6 +714,8 @@ 'libcef_dll/cpptoc/urlrequest_client_cpptoc.h', 'libcef_dll/cpptoc/v8accessor_cpptoc.cc', 'libcef_dll/cpptoc/v8accessor_cpptoc.h', + 'libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc', + 'libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h', 'libcef_dll/ctocpp/v8context_ctocpp.cc', 'libcef_dll/ctocpp/v8context_ctocpp.h', 'libcef_dll/ctocpp/v8exception_ctocpp.cc', diff --git a/include/capi/cef_v8_capi.h b/include/capi/cef_v8_capi.h index e0fc94c23..fff62cc11 100644 --- a/include/capi/cef_v8_capi.h +++ b/include/capi/cef_v8_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=e9e43167b1cf8033bd7e6ba6931213d7cf4b69b5$ +// $hash=2303574e76708e5311aede8e66eb7f1f679e0d1f$ // #ifndef CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_ @@ -355,6 +355,25 @@ typedef struct _cef_v8exception_t { int(CEF_CALLBACK* get_end_column)(struct _cef_v8exception_t* self); } cef_v8exception_t; +/// +// Callback structure that is passed to cef_v8value_t::CreateArrayBuffer. +/// +typedef struct _cef_v8array_buffer_release_callback_t { + /// + // Base structure. + /// + cef_base_ref_counted_t base; + + /// + // Called to release |buffer| when the ArrayBuffer JS object is garbage + // collected. |buffer| is the value that was passed to CreateArrayBuffer along + // with this object. + /// + void(CEF_CALLBACK* release_buffer)( + struct _cef_v8array_buffer_release_callback_t* self, + void* buffer); +} cef_v8array_buffer_release_callback_t; + /// // Structure 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 @@ -425,6 +444,11 @@ typedef struct _cef_v8value_t { /// int(CEF_CALLBACK* is_array)(struct _cef_v8value_t* self); + /// + // True if the value type is an ArrayBuffer. + /// + int(CEF_CALLBACK* is_array_buffer)(struct _cef_v8value_t* self); + /// // True if the value type is function. /// @@ -639,6 +663,25 @@ typedef struct _cef_v8value_t { /// int(CEF_CALLBACK* get_array_length)(struct _cef_v8value_t* self); + // ARRAY BUFFER METHODS - These functions are only available on ArrayBuffers. + + /// + // Returns the ReleaseCallback object associated with the ArrayBuffer or NULL + // if the ArrayBuffer was not created with CreateArrayBuffer. + /// + struct _cef_v8array_buffer_release_callback_t*( + CEF_CALLBACK* get_array_buffer_release_callback)( + struct _cef_v8value_t* self); + + /// + // 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 + // cef_v8array_buffer_release_callback_t::ReleaseBuffer will be called to + // release the underlying buffer. + /// + int(CEF_CALLBACK* neuter_array_buffer)(struct _cef_v8value_t* self); + // FUNCTION METHODS - These functions are only available on functions. /// @@ -751,6 +794,21 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_object( /// CEF_EXPORT cef_v8value_t* cef_v8value_create_array(int length); +/// +// Create a new cef_v8value_t 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 cef_v8array_buffer_release_callback_t:: +// ReleaseBuffer. This function should only be called from within the scope of a +// cef_render_process_handler_t, cef_v8handler_t or cef_v8accessor_t callback, +// or in combination with calling enter() and exit() on a stored cef_v8context_t +// reference. +/// +CEF_EXPORT cef_v8value_t* cef_v8value_create_array_buffer( + void* buffer, + size_t length, + cef_v8array_buffer_release_callback_t* release_callback); + /// // Create a new cef_v8value_t object of type function. This function should only // be called from within the scope of a cef_render_process_handler_t, diff --git a/include/cef_v8.h b/include/cef_v8.h index 819912561..2886d35f4 100644 --- a/include/cef_v8.h +++ b/include/cef_v8.h @@ -407,6 +407,21 @@ class CefV8Exception : public virtual CefBaseRefCounted { virtual int GetEndColumn() = 0; }; +/// +// Callback interface that is passed to CefV8Value::CreateArrayBuffer. +/// +/*--cef(source=client)--*/ +class CefV8ArrayBufferReleaseCallback : public virtual CefBaseRefCounted { + public: + /// + // Called to release |buffer| when the ArrayBuffer JS object is garbage + // collected. |buffer| is the value that was passed to CreateArrayBuffer along + // with this object. + /// + /*--cef()--*/ + virtual void ReleaseBuffer(void* buffer) = 0; +}; + /// // 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 @@ -493,6 +508,22 @@ class CefV8Value : public virtual CefBaseRefCounted { /*--cef()--*/ static CefRefPtr CreateArray(int 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. + /// + /*--cef()--*/ + static CefRefPtr CreateArrayBuffer( + void* buffer, + size_t length, + CefRefPtr release_callback); + /// // Create a new CefV8Value object of type function. This method should only be // called from within the scope of a CefRenderProcessHandler, CefV8Handler or @@ -571,6 +602,12 @@ class CefV8Value : public virtual CefBaseRefCounted { /*--cef()--*/ virtual bool IsArray() = 0; + /// + // True if the value type is an ArrayBuffer. + /// + /*--cef()--*/ + virtual bool IsArrayBuffer() = 0; + /// // True if the value type is function. /// @@ -793,6 +830,25 @@ class CefV8Value : public virtual CefBaseRefCounted { /*--cef()--*/ virtual int GetArrayLength() = 0; + // 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. + /// + /*--cef()--*/ + virtual CefRefPtr + GetArrayBufferReleaseCallback() = 0; + + /// + // 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. + /// + /*--cef()--*/ + virtual bool NeuterArrayBuffer() = 0; + // FUNCTION METHODS - These methods are only available on functions. /// diff --git a/libcef/renderer/v8_impl.cc b/libcef/renderer/v8_impl.cc index 302b1aa77..08e4b3a0f 100644 --- a/libcef/renderer/v8_impl.cc +++ b/libcef/renderer/v8_impl.cc @@ -304,6 +304,74 @@ class V8TrackString : public CefTrackNode { std::string string_; }; +class V8TrackArrayBuffer : public CefTrackNode { + public: + explicit V8TrackArrayBuffer( + v8::Isolate* isolate, + void* buffer, + CefRefPtr release_callback) + : isolate_(isolate), + buffer_(buffer), + release_callback_(release_callback) { + DCHECK(isolate_); + } + + ~V8TrackArrayBuffer() { + if (buffer_ != nullptr) { + release_callback_->ReleaseBuffer(buffer_); + } + isolate_->AdjustAmountOfExternalAllocatedMemory( + -static_cast(sizeof(V8TrackArrayBuffer))); + } + + CefRefPtr GetReleaseCallback() { + return release_callback_; + } + + void Neuter() { buffer_ = nullptr; } + + // Retrieve the track object for the specified V8 object. + static V8TrackArrayBuffer* Unwrap(v8::Local context, + v8::Local object) { + v8::Local value; + if (GetPrivate(context, object, kCefTrackObject, &value)) + return static_cast( + v8::External::Cast(*value)->Value()); + + return nullptr; + } + + // Attach this track object to the specified V8 object. + void AttachTo(v8::Local context, + v8::Local arrayBuffer) { + isolate_->AdjustAmountOfExternalAllocatedMemory( + static_cast(sizeof(V8TrackArrayBuffer))); + + SetPrivate(context, arrayBuffer, kCefTrackObject, + v8::External::New(isolate_, this)); + + handle_.Reset(isolate_, arrayBuffer); + handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter); + handle_.MarkIndependent(); + } + + private: + static void FirstWeakCallback( + const v8::WeakCallbackInfo& data) { + V8TrackArrayBuffer* wrapper = data.GetParameter(); + if (wrapper->buffer_ != nullptr) { + wrapper->release_callback_->ReleaseBuffer(wrapper->buffer_); + wrapper->buffer_ = nullptr; + } + wrapper->handle_.Reset(); + } + + v8::Isolate* isolate_; + void* buffer_; + CefRefPtr release_callback_; + v8::Persistent handle_; +}; + // Object wrapped in a v8::External and passed as the Data argument to // v8::FunctionTemplate::New. class V8FunctionData { @@ -1311,6 +1379,35 @@ CefRefPtr CefV8Value::CreateArray(int length) { return impl.get(); } +// static +CefRefPtr CefV8Value::CreateArrayBuffer( + void* buffer, + size_t length, + CefRefPtr release_callback) { + CEF_V8_REQUIRE_ISOLATE_RETURN(NULL); + + v8::Isolate* isolate = GetIsolateManager()->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local context = isolate->GetCurrentContext(); + if (context.IsEmpty()) { + NOTREACHED() << "not currently in a V8 context"; + return NULL; + } + + // Create a tracker object that will cause the user data reference to be + // released when the V8 object is destroyed. + V8TrackArrayBuffer* tracker = + new V8TrackArrayBuffer(isolate, buffer, release_callback); + v8::Local ab = v8::ArrayBuffer::New(isolate, buffer, length); + + // Attach the tracker object. + tracker->AttachTo(context, ab); + + CefRefPtr impl = new CefV8ValueImpl(isolate); + impl->InitObject(ab, tracker); + return impl.get(); +} + // static CefRefPtr CefV8Value::CreateFunction( const CefString& name, @@ -1571,6 +1668,16 @@ bool CefV8ValueImpl::IsArray() { } } +bool CefV8ValueImpl::IsArrayBuffer() { + CEF_V8_REQUIRE_MLT_RETURN(false); + if (type_ == TYPE_OBJECT) { + v8::HandleScope handle_scope(handle_->isolate()); + return handle_->GetNewV8Handle(false)->IsArrayBuffer(); + } else { + return false; + } +} + bool CefV8ValueImpl::IsFunction() { CEF_V8_REQUIRE_MLT_RETURN(false); if (type_ == TYPE_OBJECT) { @@ -2091,6 +2198,60 @@ int CefV8ValueImpl::GetArrayLength() { return arr->Length(); } +CefRefPtr +CefV8ValueImpl::GetArrayBufferReleaseCallback() { + CEF_V8_REQUIRE_OBJECT_RETURN(0); + + v8::Isolate* isolate = handle_->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local context = isolate->GetCurrentContext(); + if (context.IsEmpty()) { + NOTREACHED() << "not currently in a V8 context"; + return NULL; + } + v8::Local value = handle_->GetNewV8Handle(false); + if (!value->IsArrayBuffer()) { + NOTREACHED() << "V8 value is not an array buffer"; + return NULL; + } + + v8::Local obj = value->ToObject(); + + V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj); + if (tracker) + return tracker->GetReleaseCallback(); + + return NULL; +} + +bool CefV8ValueImpl::NeuterArrayBuffer() { + CEF_V8_REQUIRE_OBJECT_RETURN(0); + + v8::Isolate* isolate = handle_->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local context = isolate->GetCurrentContext(); + if (context.IsEmpty()) { + NOTREACHED() << "not currently in a V8 context"; + return false; + } + + v8::Local value = handle_->GetNewV8Handle(false); + if (!value->IsArrayBuffer()) { + NOTREACHED() << "V8 value is not an array buffer"; + return false; + } + v8::Local obj = value->ToObject(); + v8::Local arr = v8::Local::Cast(obj); + if (!arr->IsNeuterable()) { + return false; + } + arr->Neuter(); + V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj); + tracker->Neuter(); + + return true; +} + CefString CefV8ValueImpl::GetFunctionName() { CefString rv; CEF_V8_REQUIRE_OBJECT_RETURN(rv); diff --git a/libcef/renderer/v8_impl.h b/libcef/renderer/v8_impl.h index c19ee6c3a..43a7b66e2 100644 --- a/libcef/renderer/v8_impl.h +++ b/libcef/renderer/v8_impl.h @@ -227,6 +227,7 @@ class CefV8ValueImpl : public CefV8Value { bool IsString() override; bool IsObject() override; bool IsArray() override; + bool IsArrayBuffer() override; bool IsFunction() override; bool IsSame(CefRefPtr value) override; bool GetBoolValue() override; @@ -260,6 +261,9 @@ class CefV8ValueImpl : public CefV8Value { int GetExternallyAllocatedMemory() override; int AdjustExternallyAllocatedMemory(int change_in_bytes) override; int GetArrayLength() override; + CefRefPtr GetArrayBufferReleaseCallback() + override; + bool NeuterArrayBuffer() override; CefString GetFunctionName() override; CefRefPtr GetFunctionHandler() override; CefRefPtr ExecuteFunction( diff --git a/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc new file mode 100644 index 000000000..d1ebe092f --- /dev/null +++ b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=a0e352ab964b29c7b1aa22791ee38a81cd418a99$ +// + +#include "libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h" + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK v8array_buffer_release_callback_release_buffer( + struct _cef_v8array_buffer_release_callback_t* self, + void* buffer) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: buffer; type: simple_byaddr + DCHECK(buffer); + if (!buffer) + return; + + // Execute + CefV8ArrayBufferReleaseCallbackCppToC::Get(self)->ReleaseBuffer(buffer); +} + +} // namespace + +// CONSTRUCTOR - Do not edit by hand. + +CefV8ArrayBufferReleaseCallbackCppToC::CefV8ArrayBufferReleaseCallbackCppToC() { + GetStruct()->release_buffer = v8array_buffer_release_callback_release_buffer; +} + +template <> +CefRefPtr +CefCppToCRefCounted:: + UnwrapDerived(CefWrapperType type, + cef_v8array_buffer_release_callback_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template <> +base::AtomicRefCount CefCppToCRefCounted< + CefV8ArrayBufferReleaseCallbackCppToC, + CefV8ArrayBufferReleaseCallback, + cef_v8array_buffer_release_callback_t>::DebugObjCt ATOMIC_DECLARATION; +#endif + +template <> +CefWrapperType + CefCppToCRefCounted::kWrapperType = + WT_V8ARRAY_BUFFER_RELEASE_CALLBACK; diff --git a/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h new file mode 100644 index 000000000..e42a44331 --- /dev/null +++ b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=61fe643dbdefcacb37612d6611d5b3cd0d0f731a$ +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_V8ARRAY_BUFFER_RELEASE_CALLBACK_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_V8ARRAY_BUFFER_RELEASE_CALLBACK_CPPTOC_H_ +#pragma once + +#if !defined(WRAPPING_CEF_SHARED) +#error This file can be included wrapper-side only +#endif + +#include "include/capi/cef_v8_capi.h" +#include "include/cef_v8.h" +#include "libcef_dll/cpptoc/cpptoc_ref_counted.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefV8ArrayBufferReleaseCallbackCppToC + : public CefCppToCRefCounted { + public: + CefV8ArrayBufferReleaseCallbackCppToC(); +}; + +#endif // CEF_LIBCEF_DLL_CPPTOC_V8ARRAY_BUFFER_RELEASE_CALLBACK_CPPTOC_H_ diff --git a/libcef_dll/cpptoc/v8value_cpptoc.cc b/libcef_dll/cpptoc/v8value_cpptoc.cc index c6111c4af..5db18a403 100644 --- a/libcef_dll/cpptoc/v8value_cpptoc.cc +++ b/libcef_dll/cpptoc/v8value_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=d4baeb8853a8d33bde68e82a87e73e63fefb6e59$ +// $hash=b8c41c5cff5d308ad0ecbeafb38f12fae4ce06eb$ // #include "libcef_dll/cpptoc/v8value_cpptoc.h" @@ -17,6 +17,7 @@ #include "libcef_dll/cpptoc/v8exception_cpptoc.h" #include "libcef_dll/ctocpp/base_ref_counted_ctocpp.h" #include "libcef_dll/ctocpp/v8accessor_ctocpp.h" +#include "libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h" #include "libcef_dll/ctocpp/v8handler_ctocpp.h" #include "libcef_dll/ctocpp/v8interceptor_ctocpp.h" #include "libcef_dll/transfer_util.h" @@ -139,6 +140,30 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_array(int length) { return CefV8ValueCppToC::Wrap(_retval); } +CEF_EXPORT cef_v8value_t* cef_v8value_create_array_buffer( + void* buffer, + size_t length, + cef_v8array_buffer_release_callback_t* release_callback) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: buffer; type: simple_byaddr + DCHECK(buffer); + if (!buffer) + return NULL; + // Verify param: release_callback; type: refptr_diff + DCHECK(release_callback); + if (!release_callback) + return NULL; + + // Execute + CefRefPtr _retval = CefV8Value::CreateArrayBuffer( + buffer, length, + CefV8ArrayBufferReleaseCallbackCToCpp::Wrap(release_callback)); + + // Return type: refptr_same + return CefV8ValueCppToC::Wrap(_retval); +} + CEF_EXPORT cef_v8value_t* cef_v8value_create_function( const cef_string_t* name, cef_v8handler_t* handler) { @@ -319,6 +344,20 @@ int CEF_CALLBACK v8value_is_array(struct _cef_v8value_t* self) { return _retval; } +int CEF_CALLBACK v8value_is_array_buffer(struct _cef_v8value_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefV8ValueCppToC::Get(self)->IsArrayBuffer(); + + // Return type: bool + return _retval; +} + int CEF_CALLBACK v8value_is_function(struct _cef_v8value_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -806,6 +845,36 @@ int CEF_CALLBACK v8value_get_array_length(struct _cef_v8value_t* self) { return _retval; } +cef_v8array_buffer_release_callback_t* CEF_CALLBACK +v8value_get_array_buffer_release_callback(struct _cef_v8value_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefRefPtr _retval = + CefV8ValueCppToC::Get(self)->GetArrayBufferReleaseCallback(); + + // Return type: refptr_diff + return CefV8ArrayBufferReleaseCallbackCToCpp::Unwrap(_retval); +} + +int CEF_CALLBACK v8value_neuter_array_buffer(struct _cef_v8value_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefV8ValueCppToC::Get(self)->NeuterArrayBuffer(); + + // Return type: bool + return _retval; +} + cef_string_userfree_t CEF_CALLBACK v8value_get_function_name(struct _cef_v8value_t* self) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -928,6 +997,7 @@ CefV8ValueCppToC::CefV8ValueCppToC() { GetStruct()->is_string = v8value_is_string; GetStruct()->is_object = v8value_is_object; GetStruct()->is_array = v8value_is_array; + GetStruct()->is_array_buffer = v8value_is_array_buffer; GetStruct()->is_function = v8value_is_function; GetStruct()->is_same = v8value_is_same; GetStruct()->get_bool_value = v8value_get_bool_value; @@ -959,6 +1029,9 @@ CefV8ValueCppToC::CefV8ValueCppToC() { GetStruct()->adjust_externally_allocated_memory = v8value_adjust_externally_allocated_memory; GetStruct()->get_array_length = v8value_get_array_length; + GetStruct()->get_array_buffer_release_callback = + v8value_get_array_buffer_release_callback; + GetStruct()->neuter_array_buffer = v8value_neuter_array_buffer; GetStruct()->get_function_name = v8value_get_function_name; GetStruct()->get_function_handler = v8value_get_function_handler; GetStruct()->execute_function = v8value_execute_function; diff --git a/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc new file mode 100644 index 000000000..51e926c29 --- /dev/null +++ b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=4518c58051d90673ecc1fc2b9e29b70467b36c97$ +// + +#include "libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h" + +// VIRTUAL METHODS - Body may be edited by hand. + +void CefV8ArrayBufferReleaseCallbackCToCpp::ReleaseBuffer(void* buffer) { + cef_v8array_buffer_release_callback_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, release_buffer)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: buffer; type: simple_byaddr + DCHECK(buffer); + if (!buffer) + return; + + // Execute + _struct->release_buffer(_struct, buffer); +} + +// CONSTRUCTOR - Do not edit by hand. + +CefV8ArrayBufferReleaseCallbackCToCpp::CefV8ArrayBufferReleaseCallbackCToCpp() { +} + +template <> +cef_v8array_buffer_release_callback_t* +CefCToCppRefCounted:: + UnwrapDerived(CefWrapperType type, CefV8ArrayBufferReleaseCallback* c) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template <> +base::AtomicRefCount CefCToCppRefCounted< + CefV8ArrayBufferReleaseCallbackCToCpp, + CefV8ArrayBufferReleaseCallback, + cef_v8array_buffer_release_callback_t>::DebugObjCt ATOMIC_DECLARATION; +#endif + +template <> +CefWrapperType + CefCToCppRefCounted::kWrapperType = + WT_V8ARRAY_BUFFER_RELEASE_CALLBACK; diff --git a/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h new file mode 100644 index 000000000..c4a9bc6c1 --- /dev/null +++ b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h @@ -0,0 +1,40 @@ +// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=6c5b7fe181699426e51ca11b6216a1ec56e36032$ +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_V8ARRAY_BUFFER_RELEASE_CALLBACK_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_V8ARRAY_BUFFER_RELEASE_CALLBACK_CTOCPP_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) +#error This file can be included DLL-side only +#endif + +#include "include/capi/cef_v8_capi.h" +#include "include/cef_v8.h" +#include "libcef_dll/ctocpp/ctocpp_ref_counted.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefV8ArrayBufferReleaseCallbackCToCpp + : public CefCToCppRefCounted { + public: + CefV8ArrayBufferReleaseCallbackCToCpp(); + + // CefV8ArrayBufferReleaseCallback methods. + void ReleaseBuffer(void* buffer) override; +}; + +#endif // CEF_LIBCEF_DLL_CTOCPP_V8ARRAY_BUFFER_RELEASE_CALLBACK_CTOCPP_H_ diff --git a/libcef_dll/ctocpp/v8value_ctocpp.cc b/libcef_dll/ctocpp/v8value_ctocpp.cc index afb895514..3a9b5e63b 100644 --- a/libcef_dll/ctocpp/v8value_ctocpp.cc +++ b/libcef_dll/ctocpp/v8value_ctocpp.cc @@ -9,12 +9,13 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=54a9512b67fa17d33626e83e249fa27037bd92bc$ +// $hash=c08a6af7e4295bc574af45eb798e84e546f2e1a0$ // #include "libcef_dll/ctocpp/v8value_ctocpp.h" #include "libcef_dll/cpptoc/base_ref_counted_cpptoc.h" #include "libcef_dll/cpptoc/v8accessor_cpptoc.h" +#include "libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h" #include "libcef_dll/cpptoc/v8handler_cpptoc.h" #include "libcef_dll/cpptoc/v8interceptor_cpptoc.h" #include "libcef_dll/ctocpp/v8context_ctocpp.h" @@ -131,6 +132,30 @@ CefRefPtr CefV8Value::CreateArray(int length) { return CefV8ValueCToCpp::Wrap(_retval); } +CefRefPtr CefV8Value::CreateArrayBuffer( + void* buffer, + size_t length, + CefRefPtr release_callback) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: buffer; type: simple_byaddr + DCHECK(buffer); + if (!buffer) + return NULL; + // Verify param: release_callback; type: refptr_diff + DCHECK(release_callback.get()); + if (!release_callback.get()) + return NULL; + + // Execute + cef_v8value_t* _retval = cef_v8value_create_array_buffer( + buffer, length, + CefV8ArrayBufferReleaseCallbackCppToC::Wrap(release_callback)); + + // Return type: refptr_same + return CefV8ValueCToCpp::Wrap(_retval); +} + CefRefPtr CefV8Value::CreateFunction( const CefString& name, CefRefPtr handler) { @@ -309,6 +334,20 @@ bool CefV8ValueCToCpp::IsArray() { return _retval ? true : false; } +bool CefV8ValueCToCpp::IsArrayBuffer() { + cef_v8value_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, is_array_buffer)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = _struct->is_array_buffer(_struct); + + // Return type: bool + return _retval ? true : false; +} + bool CefV8ValueCToCpp::IsFunction() { cef_v8value_t* _struct = GetStruct(); if (CEF_MEMBER_MISSING(_struct, is_function)) @@ -784,6 +823,36 @@ int CefV8ValueCToCpp::GetArrayLength() { return _retval; } +CefRefPtr +CefV8ValueCToCpp::GetArrayBufferReleaseCallback() { + cef_v8value_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_array_buffer_release_callback)) + return NULL; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_v8array_buffer_release_callback_t* _retval = + _struct->get_array_buffer_release_callback(_struct); + + // Return type: refptr_diff + return CefV8ArrayBufferReleaseCallbackCppToC::Unwrap(_retval); +} + +bool CefV8ValueCToCpp::NeuterArrayBuffer() { + cef_v8value_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, neuter_array_buffer)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = _struct->neuter_array_buffer(_struct); + + // Return type: bool + return _retval ? true : false; +} + CefString CefV8ValueCToCpp::GetFunctionName() { cef_v8value_t* _struct = GetStruct(); if (CEF_MEMBER_MISSING(_struct, get_function_name)) diff --git a/libcef_dll/ctocpp/v8value_ctocpp.h b/libcef_dll/ctocpp/v8value_ctocpp.h index 674e25737..7e5e786c8 100644 --- a/libcef_dll/ctocpp/v8value_ctocpp.h +++ b/libcef_dll/ctocpp/v8value_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=8a913ff3ac0743621e969fed20ce713804ac4f16$ +// $hash=72b98313f1c00f864fd01694eb741f066ae2c5f4$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_ @@ -44,6 +44,7 @@ class CefV8ValueCToCpp bool IsString() OVERRIDE; bool IsObject() OVERRIDE; bool IsArray() OVERRIDE; + bool IsArrayBuffer() OVERRIDE; bool IsFunction() OVERRIDE; bool IsSame(CefRefPtr that) OVERRIDE; bool GetBoolValue() OVERRIDE; @@ -77,6 +78,9 @@ class CefV8ValueCToCpp int GetExternallyAllocatedMemory() OVERRIDE; int AdjustExternallyAllocatedMemory(int change_in_bytes) OVERRIDE; int GetArrayLength() OVERRIDE; + CefRefPtr GetArrayBufferReleaseCallback() + OVERRIDE; + bool NeuterArrayBuffer() OVERRIDE; CefString GetFunctionName() OVERRIDE; CefRefPtr GetFunctionHandler() OVERRIDE; CefRefPtr ExecuteFunction( diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 7aad5a5db..b6d27e94e 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=8fb3e1af64274b34482ee34c75a6196654104360$ +// $hash=34ae05a5b71f5f9ede44fb859074e9ffcd7b65ad$ // #include "include/capi/cef_app_capi.h" @@ -158,6 +158,7 @@ #include "libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h" #include "libcef_dll/ctocpp/urlrequest_client_ctocpp.h" #include "libcef_dll/ctocpp/v8accessor_ctocpp.h" +#include "libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h" #include "libcef_dll/ctocpp/v8handler_ctocpp.h" #include "libcef_dll/ctocpp/v8interceptor_ctocpp.h" #include "libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h" @@ -372,6 +373,8 @@ CEF_EXPORT void cef_shutdown() { DCHECK(base::AtomicRefCountIsZero(&CefURLRequestClientCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefURLRequestCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8AccessorCToCpp::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero( + &CefV8ArrayBufferReleaseCallbackCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ContextCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ExceptionCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8HandlerCToCpp::DebugObjCt)); diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 5994fbdc2..9380d64aa 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=07d31c969dc527db8df550827d750aefa0abf1b8$ +// $hash=0549060b3d0b129aa1d4b0824eeacf3af9d3d5ab$ // #include "include/capi/cef_app_capi.h" @@ -87,6 +87,7 @@ #include "libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h" #include "libcef_dll/cpptoc/urlrequest_client_cpptoc.h" #include "libcef_dll/cpptoc/v8accessor_cpptoc.h" +#include "libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h" #include "libcef_dll/cpptoc/v8handler_cpptoc.h" #include "libcef_dll/cpptoc/v8interceptor_cpptoc.h" #include "libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h" @@ -363,6 +364,8 @@ CEF_GLOBAL void CefShutdown() { DCHECK(base::AtomicRefCountIsZero(&CefURLRequestCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefURLRequestClientCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8AccessorCppToC::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero( + &CefV8ArrayBufferReleaseCallbackCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ContextCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ExceptionCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8HandlerCppToC::DebugObjCt)); diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index 30bc3e589..62382cbec 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=3fe3af71072987e46db28d1a94b8b6a9ad7d9e2a$ +// $hash=47f1724d1f28c8295717e5df6ce8f5f8602ce1d5$ // #ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_ @@ -137,6 +137,7 @@ enum CefWrapperType { WT_URLREQUEST, WT_URLREQUEST_CLIENT, WT_V8ACCESSOR, + WT_V8ARRAY_BUFFER_RELEASE_CALLBACK, WT_V8CONTEXT, WT_V8EXCEPTION, WT_V8HANDLER, diff --git a/tests/ceftests/v8_unittest.cc b/tests/ceftests/v8_unittest.cc index f91fdd4bd..ad6982304 100644 --- a/tests/ceftests/v8_unittest.cc +++ b/tests/ceftests/v8_unittest.cc @@ -57,6 +57,8 @@ enum V8TestMode { V8TEST_EMPTY_STRING_CREATE, V8TEST_ARRAY_CREATE, V8TEST_ARRAY_VALUE, + V8TEST_ARRAY_BUFFER, + V8TEST_ARRAY_BUFFER_VALUE, V8TEST_OBJECT_CREATE, V8TEST_OBJECT_USERDATA, V8TEST_OBJECT_ACCESSOR, @@ -159,6 +161,12 @@ class V8RendererTest : public ClientAppRenderer::Delegate, case V8TEST_ARRAY_VALUE: RunArrayValueTest(); break; + case V8TEST_ARRAY_BUFFER: + RunArrayBufferTest(); + break; + case V8TEST_ARRAY_BUFFER_VALUE: + RunArrayBufferValueTest(); + break; case V8TEST_OBJECT_CREATE: RunObjectCreateTest(); break; @@ -543,6 +551,117 @@ class V8RendererTest : public ClientAppRenderer::Delegate, DestroyTest(); } + void RunArrayBufferTest() { + class TestArrayBufferReleaseCallback + : public CefV8ArrayBufferReleaseCallback { + public: + TestArrayBufferReleaseCallback(bool* destructorCalled, + bool* releaseBufferCalled) + : destructorCalled_(destructorCalled), + releaseBufferCalled_(releaseBufferCalled) {} + + ~TestArrayBufferReleaseCallback() { *destructorCalled_ = true; } + + void ReleaseBuffer(void* buffer) { *releaseBufferCalled_ = true; } + + IMPLEMENT_REFCOUNTING(TestArrayBufferReleaseCallback); + + private: + bool* destructorCalled_; + bool* releaseBufferCalled_; + }; + + CefRefPtr context = GetContext(); + + bool destructorCalled = false; + bool releaseBufferCalled = false; + + bool neuteredDestructorCalled = false; + bool neuteredReleaseBufferCalled = false; + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + { + int static_data[16]; + CefRefPtr value; + CefRefPtr release_callback = + new TestArrayBufferReleaseCallback(&destructorCalled, + &releaseBufferCalled); + + CefRefPtr neuteredValue; + CefRefPtr neuteredReleaseCallback = + new TestArrayBufferReleaseCallback(&neuteredDestructorCalled, + &neuteredReleaseBufferCalled); + value = CefV8Value::CreateArrayBuffer(static_data, sizeof(static_data), + release_callback); + neuteredValue = CefV8Value::CreateArrayBuffer( + static_data, sizeof(static_data), neuteredReleaseCallback); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsArrayBuffer()); + EXPECT_TRUE(value->IsObject()); + EXPECT_FALSE(value->HasValue(0)); + EXPECT_FALSE(destructorCalled); + EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr); + EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value + ->GetArrayBufferReleaseCallback() + .get()) == release_callback); + + EXPECT_TRUE(neuteredValue->NeuterArrayBuffer()); + } + // Exit the V8 context. + EXPECT_TRUE(destructorCalled); + EXPECT_TRUE(releaseBufferCalled); + EXPECT_TRUE(neuteredDestructorCalled); + EXPECT_FALSE(neuteredReleaseBufferCalled); + EXPECT_TRUE(context->Exit()); + DestroyTest(); + } + + void RunArrayBufferValueTest() { + class TestArrayBufferReleaseCallback + : public CefV8ArrayBufferReleaseCallback { + public: + TestArrayBufferReleaseCallback() {} + + ~TestArrayBufferReleaseCallback() {} + + void ReleaseBuffer(void* buffer) {} + + IMPLEMENT_REFCOUNTING(TestArrayBufferReleaseCallback); + }; + + CefRefPtr context = GetContext(); + + // Enter the V8 context. + CefRefPtr value; + + CefRefPtr owner = + new TestArrayBufferReleaseCallback(); + EXPECT_TRUE(context->Enter()); + int static_data[16]; + static_data[0] = 3; + value = + CefV8Value::CreateArrayBuffer(static_data, sizeof(static_data), owner); + + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + object->SetValue("arr", value, V8_PROPERTY_ATTRIBUTE_NONE); + std::string test = + "let data = new Int32Array(window.arr); data[0] += data.length"; + CefRefPtr retval; + CefRefPtr exception; + EXPECT_TRUE(context->Eval(test, CefString(), 0, retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + EXPECT_TRUE(static_data[0] == 19); + EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr); + EXPECT_TRUE(value->NeuterArrayBuffer()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + DestroyTest(); + } + void RunObjectCreateTest() { CefRefPtr context = GetContext(); @@ -2972,6 +3091,8 @@ V8_TEST(StringCreate, V8TEST_STRING_CREATE); V8_TEST(EmptyStringCreate, V8TEST_EMPTY_STRING_CREATE); V8_TEST(ArrayCreate, V8TEST_ARRAY_CREATE); V8_TEST(ArrayValue, V8TEST_ARRAY_VALUE); +V8_TEST(ArrayBuffer, V8TEST_ARRAY_BUFFER); +V8_TEST(ArrayBufferValue, V8TEST_ARRAY_BUFFER_VALUE); V8_TEST(ObjectCreate, V8TEST_OBJECT_CREATE); V8_TEST(ObjectUserData, V8TEST_OBJECT_USERDATA); V8_TEST(ObjectAccessor, V8TEST_OBJECT_ACCESSOR);