From e006ec0ab58f2f1e132b82ba6408edecd3ef4101 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Thu, 27 Oct 2016 13:23:56 -0400 Subject: [PATCH] Add V8 interceptor support (issue #1159) --- AUTHORS.txt | 1 + cef_paths.gypi | 4 + include/capi/cef_v8_capi.h | 77 ++- include/cef_v8.h | 78 ++- libcef/renderer/v8_impl.cc | 104 ++- libcef_dll/cpptoc/v8interceptor_cpptoc.cc | 234 +++++++ libcef_dll/cpptoc/v8interceptor_cpptoc.h | 35 + libcef_dll/cpptoc/v8value_cpptoc.cc | 10 +- libcef_dll/ctocpp/v8interceptor_ctocpp.cc | 190 ++++++ libcef_dll/ctocpp/v8interceptor_ctocpp.h | 45 ++ libcef_dll/ctocpp/v8value_ctocpp.cc | 9 +- libcef_dll/libcef_dll.cc | 2 + libcef_dll/wrapper/libcef_dll_wrapper.cc | 2 + libcef_dll/wrapper_types.h | 1 + tests/cefclient/renderer/performance_test.cc | 2 +- .../renderer/performance_test_tests.cc | 51 +- tests/unittests/v8_unittest.cc | 646 +++++++++++++++++- 17 files changed, 1454 insertions(+), 37 deletions(-) create mode 100644 libcef_dll/cpptoc/v8interceptor_cpptoc.cc create mode 100644 libcef_dll/cpptoc/v8interceptor_cpptoc.h create mode 100644 libcef_dll/ctocpp/v8interceptor_ctocpp.cc create mode 100644 libcef_dll/ctocpp/v8interceptor_ctocpp.h diff --git a/AUTHORS.txt b/AUTHORS.txt index 1af953e02..c326ef5f3 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -29,3 +29,4 @@ Felix Bruns YuTeh Shen Andrei Kurushin Gonzo Berman +Jakub Trzebiatowski diff --git a/cef_paths.gypi b/cef_paths.gypi index bd6740453..656bcbaeb 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -400,6 +400,8 @@ 'libcef_dll/cpptoc/v8exception_cpptoc.h', 'libcef_dll/ctocpp/v8handler_ctocpp.cc', 'libcef_dll/ctocpp/v8handler_ctocpp.h', + 'libcef_dll/ctocpp/v8interceptor_ctocpp.cc', + 'libcef_dll/ctocpp/v8interceptor_ctocpp.h', 'libcef_dll/cpptoc/v8stack_frame_cpptoc.cc', 'libcef_dll/cpptoc/v8stack_frame_cpptoc.h', 'libcef_dll/cpptoc/v8stack_trace_cpptoc.cc', @@ -654,6 +656,8 @@ 'libcef_dll/ctocpp/v8exception_ctocpp.h', 'libcef_dll/cpptoc/v8handler_cpptoc.cc', 'libcef_dll/cpptoc/v8handler_cpptoc.h', + 'libcef_dll/cpptoc/v8interceptor_cpptoc.cc', + 'libcef_dll/cpptoc/v8interceptor_cpptoc.h', 'libcef_dll/ctocpp/v8stack_frame_ctocpp.cc', 'libcef_dll/ctocpp/v8stack_frame_ctocpp.h', 'libcef_dll/ctocpp/v8stack_trace_ctocpp.cc', diff --git a/include/capi/cef_v8_capi.h b/include/capi/cef_v8_capi.h index 7b85b2774..4028ad482 100644 --- a/include/capi/cef_v8_capi.h +++ b/include/capi/cef_v8_capi.h @@ -213,6 +213,70 @@ typedef struct _cef_v8accessor_t { } cef_v8accessor_t; +/// +// Structure that should be implemented to handle V8 interceptor calls. The +// functions of this structure will be called on the thread associated with the +// V8 interceptor. Interceptor's named property handlers (with first argument of +// type CefString) are called when object is indexed by string. Indexed property +// handlers (with first argument of type int) are called when object is indexed +// by integer. +/// +typedef struct _cef_v8interceptor_t { + /// + // Base structure. + /// + cef_base_t base; + + /// + // Handle retrieval of the interceptor value identified by |name|. |object| is + // the receiver ('this' object) of the interceptor. If retrieval succeeds, set + // |retval| to the return value. If the requested value does not exist, don't + // set either |retval| or |exception|. If retrieval fails, set |exception| to + // the exception that will be thrown. If the property has an associated + // accessor, it will be called only if you don't set |retval|. Return true (1) + // if interceptor retrieval was handled, false (0) otherwise. + /// + int (CEF_CALLBACK *get_byname)(struct _cef_v8interceptor_t* self, + const cef_string_t* name, struct _cef_v8value_t* object, + struct _cef_v8value_t** retval, cef_string_t* exception); + + /// + // Handle retrieval of the interceptor value identified by |index|. |object| + // is the receiver ('this' object) of the interceptor. If retrieval succeeds, + // set |retval| to the return value. If the requested value does not exist, + // don't set either |retval| or |exception|. If retrieval fails, set + // |exception| to the exception that will be thrown. Return true (1) if + // interceptor retrieval was handled, false (0) otherwise. + /// + int (CEF_CALLBACK *get_byindex)(struct _cef_v8interceptor_t* self, int index, + struct _cef_v8value_t* object, struct _cef_v8value_t** retval, + cef_string_t* exception); + + /// + // Handle assignment of the interceptor value identified by |name|. |object| + // is the receiver ('this' object) of the interceptor. |value| is the new + // value being assigned to the interceptor. If assignment fails, set + // |exception| to the exception that will be thrown. This setter will always + // be called, even when the property has an associated accessor. Return true + // (1) if interceptor assignment was handled, false (0) otherwise. + /// + int (CEF_CALLBACK *set_byname)(struct _cef_v8interceptor_t* self, + const cef_string_t* name, struct _cef_v8value_t* object, + struct _cef_v8value_t* value, cef_string_t* exception); + + /// + // Handle assignment of the interceptor value identified by |index|. |object| + // is the receiver ('this' object) of the interceptor. |value| is the new + // value being assigned to the interceptor. If assignment fails, set + // |exception| to the exception that will be thrown. Return true (1) if + // interceptor assignment was handled, false (0) otherwise. + /// + int (CEF_CALLBACK *set_byindex)(struct _cef_v8interceptor_t* self, int index, + struct _cef_v8value_t* object, struct _cef_v8value_t* value, + cef_string_t* exception); +} cef_v8interceptor_t; + + /// // Structure representing a V8 exception. The functions of this structure may be // called on any render process thread. @@ -654,13 +718,14 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_date(const cef_time_t* date); CEF_EXPORT cef_v8value_t* cef_v8value_create_string(const cef_string_t* value); /// -// Create a new cef_v8value_t object of type object with optional accessor. 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. +// Create a new cef_v8value_t object of type object with optional accessor +// and/or interceptor. 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_object(cef_v8accessor_t* accessor); +CEF_EXPORT cef_v8value_t* cef_v8value_create_object(cef_v8accessor_t* accessor, + cef_v8interceptor_t* interceptor); /// // Create a new cef_v8value_t object of type array with the specified |length|. diff --git a/include/cef_v8.h b/include/cef_v8.h index a0f64d074..a11073e74 100644 --- a/include/cef_v8.h +++ b/include/cef_v8.h @@ -281,6 +281,74 @@ class CefV8Accessor : public virtual CefBase { CefString& exception) =0; }; +/// +// Interface that should be implemented to handle V8 interceptor calls. The +// methods of this class will be called on the thread associated with the V8 +// interceptor. Interceptor's named property handlers (with first argument of +// type CefString) are called when object is indexed by string. Indexed property +// handlers (with first argument of type int) are called when object is indexed +// by integer. +/// +/*--cef(source=client)--*/ +class CefV8Interceptor : public virtual CefBase { +public: + /// + // Handle retrieval of the interceptor value identified by |name|. |object| is + // the receiver ('this' object) of the interceptor. If retrieval succeeds, set + // |retval| to the return value. If the requested value does not exist, don't + // set either |retval| or |exception|. If retrieval fails, set |exception| to + // the exception that will be thrown. If the property has an associated + // accessor, it will be called only if you don't set |retval|. + // Return true if interceptor retrieval was handled, false otherwise. + /// + /*--cef(capi_name=get_byname)--*/ + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) =0; + + /// + // Handle retrieval of the interceptor value identified by |index|. |object| + // is the receiver ('this' object) of the interceptor. If retrieval succeeds, + // set |retval| to the return value. If the requested value does not exist, + // don't set either |retval| or |exception|. If retrieval fails, set + // |exception| to the exception that will be thrown. + // Return true if interceptor retrieval was handled, false otherwise. + /// + /*--cef(capi_name=get_byindex,index_param=index)--*/ + virtual bool Get(int index, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) =0; + + /// + // Handle assignment of the interceptor value identified by |name|. |object| + // is the receiver ('this' object) of the interceptor. |value| is the new + // value being assigned to the interceptor. If assignment fails, set + // |exception| to the exception that will be thrown. This setter will always + // be called, even when the property has an associated accessor. + // Return true if interceptor assignment was handled, false otherwise. + /// + /*--cef(capi_name=set_byname)--*/ + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) =0; + + /// + // Handle assignment of the interceptor value identified by |index|. |object| + // is the receiver ('this' object) of the interceptor. |value| is the new + // value being assigned to the interceptor. If assignment fails, set + // |exception| to the exception that will be thrown. + // Return true if interceptor assignment was handled, false otherwise. + /// + /*--cef(capi_name=set_byindex,index_param=index)--*/ + virtual bool Set(int index, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) =0; +}; + /// // Class representing a V8 exception. The methods of this class may be called on // any render process thread. @@ -408,14 +476,16 @@ class CefV8Value : public virtual CefBase { static CefRefPtr CreateString(const CefString& value); /// - // Create a new CefV8Value object of type object with optional accessor. This - // method should only be called from within the scope of a + // 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. /// - /*--cef(optional_param=accessor)--*/ - static CefRefPtr CreateObject(CefRefPtr accessor); + /*--cef(optional_param=accessor, optional_param=interceptor)--*/ + static CefRefPtr CreateObject( + CefRefPtr accessor, + CefRefPtr interceptor); /// // Create a new CefV8Value object of type array with the specified |length|. diff --git a/libcef/renderer/v8_impl.cc b/libcef/renderer/v8_impl.cc index 75efa4171..825e58812 100644 --- a/libcef/renderer/v8_impl.cc +++ b/libcef/renderer/v8_impl.cc @@ -337,6 +337,14 @@ class V8TrackObject : public CefTrackNode { return accessor_; } + inline void SetInterceptor(CefRefPtr interceptor) { + interceptor_ = interceptor; + } + + inline CefRefPtr GetInterceptor() { + return interceptor_; + } + inline void SetHandler(CefRefPtr handler) { handler_ = handler; } @@ -373,6 +381,7 @@ class V8TrackObject : public CefTrackNode { private: v8::Isolate* isolate_; CefRefPtr accessor_; + CefRefPtr interceptor_; CefRefPtr handler_; CefRefPtr user_data_; int external_memory_; @@ -645,6 +654,77 @@ void AccessorNameSetterCallbackImpl( } } +// Two helper functions for V8 Interceptor callbacks. +CefString PropertyToIndex(v8::Local str) { + CefString name; + GetCefString(str, name); + return name; +} + +int PropertyToIndex(uint32_t index) { + return static_cast(index); +} + +// V8 Interceptor callbacks. +// T == v8::Local for named property handlers and +// T == uint32_t for indexed property handlers +template +void InterceptorGetterCallbackImpl( + T property, + const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::Local context = isolate->GetCurrentContext(); + + v8::Handle obj = info.This(); + CefRefPtr interceptorPtr; + + V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj); + if (tracker) + interceptorPtr = tracker->GetInterceptor(); + if (!interceptorPtr.get()) + return; + + CefRefPtr object = new CefV8ValueImpl(isolate, context, obj); + CefRefPtr retval; + CefString exception; + interceptorPtr->Get(PropertyToIndex(property), object, retval, exception); + if (!exception.empty()) { + info.GetReturnValue().Set(isolate->ThrowException( + v8::Exception::Error(GetV8String(isolate, exception)))); + } else { + CefV8ValueImpl* retval_impl = static_cast(retval.get()); + if (retval_impl && retval_impl->IsValid()) { + info.GetReturnValue().Set(retval_impl->GetV8Value(true)); + } + } +} + +template +void InterceptorSetterCallbackImpl( + T property, + v8::Local value, + const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::Local context = isolate->GetCurrentContext(); + v8::Handle obj = info.This(); + CefRefPtr interceptorPtr; + + V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj); + if (tracker) + interceptorPtr = tracker->GetInterceptor(); + + if (!interceptorPtr.get()) + return; + CefRefPtr object = new CefV8ValueImpl(isolate, context, obj); + CefRefPtr cefValue = new CefV8ValueImpl(isolate, context, value); + CefString exception; + interceptorPtr->Set(PropertyToIndex(property), object, cefValue, exception); + if (!exception.empty()) { + isolate->ThrowException( + v8::Exception::Error(GetV8String(isolate, exception))); + } +} + // V8 extension registration. class ExtensionWrapper : public v8::Extension { @@ -1260,7 +1340,8 @@ CefRefPtr CefV8Value::CreateString(const CefString& value) { // static CefRefPtr CefV8Value::CreateObject( - CefRefPtr accessor) { + CefRefPtr accessor, + CefRefPtr interceptor) { CEF_V8_REQUIRE_ISOLATE_RETURN(NULL); v8::Isolate* isolate = GetIsolateManager()->isolate(); @@ -1272,13 +1353,28 @@ CefRefPtr CefV8Value::CreateObject( return NULL; } - // Create the new V8 object. - v8::Local obj = v8::Object::New(isolate); + // Create the new V8 object. If an interceptor is passed, create object from + // template and set property handlers. + v8::Local obj; + if (interceptor.get()) { + v8::Local tmpl = v8::ObjectTemplate::New(isolate); + tmpl->SetNamedPropertyHandler( + InterceptorGetterCallbackImpl>, + InterceptorSetterCallbackImpl>); + + tmpl->SetIndexedPropertyHandler(InterceptorGetterCallbackImpl, + InterceptorSetterCallbackImpl); + obj = tmpl->NewInstance(); + } else { + obj = v8::Object::New(isolate); + } // Create a tracker object that will cause the user data and/or accessor - // reference to be released when the V8 object is destroyed. + // and/or interceptor reference to be released when the V8 object is + // destroyed. V8TrackObject* tracker = new V8TrackObject(isolate); tracker->SetAccessor(accessor); + tracker->SetInterceptor(interceptor); // Attach the tracker object. tracker->AttachTo(context, obj); diff --git a/libcef_dll/cpptoc/v8interceptor_cpptoc.cc b/libcef_dll/cpptoc/v8interceptor_cpptoc.cc new file mode 100644 index 000000000..0aad50af2 --- /dev/null +++ b/libcef_dll/cpptoc/v8interceptor_cpptoc.cc @@ -0,0 +1,234 @@ +// Copyright (c) 2016 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. +// + +#include "libcef_dll/cpptoc/v8interceptor_cpptoc.h" +#include "libcef_dll/ctocpp/v8value_ctocpp.h" + + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +int CEF_CALLBACK v8interceptor_get_byname(struct _cef_v8interceptor_t* self, + const cef_string_t* name, struct _cef_v8value_t* object, + struct _cef_v8value_t** retval, cef_string_t* exception) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: name; type: string_byref_const + DCHECK(name); + if (!name) + return 0; + // Verify param: object; type: refptr_diff + DCHECK(object); + if (!object) + return 0; + // Verify param: retval; type: refptr_diff_byref + DCHECK(retval); + if (!retval) + return 0; + // Verify param: exception; type: string_byref + DCHECK(exception); + if (!exception) + return 0; + + // Translate param: retval; type: refptr_diff_byref + CefRefPtr retvalPtr; + if (retval && *retval) + retvalPtr = CefV8ValueCToCpp::Wrap(*retval); + CefV8Value* retvalOrig = retvalPtr.get(); + // Translate param: exception; type: string_byref + CefString exceptionStr(exception); + + // Execute + bool _retval = CefV8InterceptorCppToC::Get(self)->Get( + CefString(name), + CefV8ValueCToCpp::Wrap(object), + retvalPtr, + exceptionStr); + + // Restore param: retval; type: refptr_diff_byref + if (retval) { + if (retvalPtr.get()) { + if (retvalPtr.get() != retvalOrig) { + *retval = CefV8ValueCToCpp::Unwrap(retvalPtr); + } + } else { + *retval = NULL; + } + } + + // Return type: bool + return _retval; +} + +int CEF_CALLBACK v8interceptor_get_byindex(struct _cef_v8interceptor_t* self, + int index, struct _cef_v8value_t* object, struct _cef_v8value_t** retval, + cef_string_t* exception) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: index; type: simple_byval + DCHECK_GE(index, 0); + if (index < 0) + return 0; + // Verify param: object; type: refptr_diff + DCHECK(object); + if (!object) + return 0; + // Verify param: retval; type: refptr_diff_byref + DCHECK(retval); + if (!retval) + return 0; + // Verify param: exception; type: string_byref + DCHECK(exception); + if (!exception) + return 0; + + // Translate param: retval; type: refptr_diff_byref + CefRefPtr retvalPtr; + if (retval && *retval) + retvalPtr = CefV8ValueCToCpp::Wrap(*retval); + CefV8Value* retvalOrig = retvalPtr.get(); + // Translate param: exception; type: string_byref + CefString exceptionStr(exception); + + // Execute + bool _retval = CefV8InterceptorCppToC::Get(self)->Get( + index, + CefV8ValueCToCpp::Wrap(object), + retvalPtr, + exceptionStr); + + // Restore param: retval; type: refptr_diff_byref + if (retval) { + if (retvalPtr.get()) { + if (retvalPtr.get() != retvalOrig) { + *retval = CefV8ValueCToCpp::Unwrap(retvalPtr); + } + } else { + *retval = NULL; + } + } + + // Return type: bool + return _retval; +} + +int CEF_CALLBACK v8interceptor_set_byname(struct _cef_v8interceptor_t* self, + const cef_string_t* name, struct _cef_v8value_t* object, + struct _cef_v8value_t* value, cef_string_t* exception) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: name; type: string_byref_const + DCHECK(name); + if (!name) + return 0; + // Verify param: object; type: refptr_diff + DCHECK(object); + if (!object) + return 0; + // Verify param: value; type: refptr_diff + DCHECK(value); + if (!value) + return 0; + // Verify param: exception; type: string_byref + DCHECK(exception); + if (!exception) + return 0; + + // Translate param: exception; type: string_byref + CefString exceptionStr(exception); + + // Execute + bool _retval = CefV8InterceptorCppToC::Get(self)->Set( + CefString(name), + CefV8ValueCToCpp::Wrap(object), + CefV8ValueCToCpp::Wrap(value), + exceptionStr); + + // Return type: bool + return _retval; +} + +int CEF_CALLBACK v8interceptor_set_byindex(struct _cef_v8interceptor_t* self, + int index, struct _cef_v8value_t* object, struct _cef_v8value_t* value, + cef_string_t* exception) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: index; type: simple_byval + DCHECK_GE(index, 0); + if (index < 0) + return 0; + // Verify param: object; type: refptr_diff + DCHECK(object); + if (!object) + return 0; + // Verify param: value; type: refptr_diff + DCHECK(value); + if (!value) + return 0; + // Verify param: exception; type: string_byref + DCHECK(exception); + if (!exception) + return 0; + + // Translate param: exception; type: string_byref + CefString exceptionStr(exception); + + // Execute + bool _retval = CefV8InterceptorCppToC::Get(self)->Set( + index, + CefV8ValueCToCpp::Wrap(object), + CefV8ValueCToCpp::Wrap(value), + exceptionStr); + + // Return type: bool + return _retval; +} + +} // namespace + + +// CONSTRUCTOR - Do not edit by hand. + +CefV8InterceptorCppToC::CefV8InterceptorCppToC() { + GetStruct()->get_byname = v8interceptor_get_byname; + GetStruct()->get_byindex = v8interceptor_get_byindex; + GetStruct()->set_byname = v8interceptor_set_byname; + GetStruct()->set_byindex = v8interceptor_set_byindex; +} + +template<> CefRefPtr CefCppToC::UnwrapDerived(CefWrapperType type, + cef_v8interceptor_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template<> base::AtomicRefCount CefCppToC::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCppToC::kWrapperType = WT_V8INTERCEPTOR; diff --git a/libcef_dll/cpptoc/v8interceptor_cpptoc.h b/libcef_dll/cpptoc/v8interceptor_cpptoc.h new file mode 100644 index 000000000..431fb5aab --- /dev/null +++ b/libcef_dll/cpptoc/v8interceptor_cpptoc.h @@ -0,0 +1,35 @@ +// Copyright (c) 2016 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. +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_V8INTERCEPTOR_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_V8INTERCEPTOR_CPPTOC_H_ +#pragma once + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef_v8.h" +#include "include/capi/cef_v8_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefV8InterceptorCppToC + : public CefCppToC { + public: + CefV8InterceptorCppToC(); +}; + +#endif // USING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CPPTOC_V8INTERCEPTOR_CPPTOC_H_ diff --git a/libcef_dll/cpptoc/v8value_cpptoc.cc b/libcef_dll/cpptoc/v8value_cpptoc.cc index fec5f09de..1ea9e5215 100644 --- a/libcef_dll/cpptoc/v8value_cpptoc.cc +++ b/libcef_dll/cpptoc/v8value_cpptoc.cc @@ -16,6 +16,7 @@ #include "libcef_dll/ctocpp/base_ctocpp.h" #include "libcef_dll/ctocpp/v8accessor_ctocpp.h" #include "libcef_dll/ctocpp/v8handler_ctocpp.h" +#include "libcef_dll/ctocpp/v8interceptor_ctocpp.h" #include "libcef_dll/transfer_util.h" @@ -117,15 +118,16 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_string(const cef_string_t* value) { return CefV8ValueCppToC::Wrap(_retval); } -CEF_EXPORT cef_v8value_t* cef_v8value_create_object( - cef_v8accessor_t* accessor) { +CEF_EXPORT cef_v8value_t* cef_v8value_create_object(cef_v8accessor_t* accessor, + cef_v8interceptor_t* interceptor) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING - // Unverified params: accessor + // Unverified params: accessor, interceptor // Execute CefRefPtr _retval = CefV8Value::CreateObject( - CefV8AccessorCToCpp::Wrap(accessor)); + CefV8AccessorCToCpp::Wrap(accessor), + CefV8InterceptorCToCpp::Wrap(interceptor)); // Return type: refptr_same return CefV8ValueCppToC::Wrap(_retval); diff --git a/libcef_dll/ctocpp/v8interceptor_ctocpp.cc b/libcef_dll/ctocpp/v8interceptor_ctocpp.cc new file mode 100644 index 000000000..6a4f36445 --- /dev/null +++ b/libcef_dll/ctocpp/v8interceptor_ctocpp.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2016 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. +// + +#include "libcef_dll/cpptoc/v8value_cpptoc.h" +#include "libcef_dll/ctocpp/v8interceptor_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +bool CefV8InterceptorCToCpp::Get(const CefString& name, + const CefRefPtr object, CefRefPtr& retval, + CefString& exception) { + cef_v8interceptor_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_byname)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: name; type: string_byref_const + DCHECK(!name.empty()); + if (name.empty()) + return false; + // Verify param: object; type: refptr_diff + DCHECK(object.get()); + if (!object.get()) + return false; + + // Translate param: retval; type: refptr_diff_byref + cef_v8value_t* retvalStruct = NULL; + if (retval.get()) + retvalStruct = CefV8ValueCppToC::Wrap(retval); + cef_v8value_t* retvalOrig = retvalStruct; + + // Execute + int _retval = _struct->get_byname(_struct, + name.GetStruct(), + CefV8ValueCppToC::Wrap(object), + &retvalStruct, + exception.GetWritableStruct()); + + // Restore param:retval; type: refptr_diff_byref + if (retvalStruct) { + if (retvalStruct != retvalOrig) { + retval = CefV8ValueCppToC::Unwrap(retvalStruct); + } + } else { + retval = NULL; + } + + // Return type: bool + return _retval?true:false; +} + +bool CefV8InterceptorCToCpp::Get(int index, const CefRefPtr object, + CefRefPtr& retval, CefString& exception) { + cef_v8interceptor_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_byindex)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: index; type: simple_byval + DCHECK_GE(index, 0); + if (index < 0) + return false; + // Verify param: object; type: refptr_diff + DCHECK(object.get()); + if (!object.get()) + return false; + + // Translate param: retval; type: refptr_diff_byref + cef_v8value_t* retvalStruct = NULL; + if (retval.get()) + retvalStruct = CefV8ValueCppToC::Wrap(retval); + cef_v8value_t* retvalOrig = retvalStruct; + + // Execute + int _retval = _struct->get_byindex(_struct, + index, + CefV8ValueCppToC::Wrap(object), + &retvalStruct, + exception.GetWritableStruct()); + + // Restore param:retval; type: refptr_diff_byref + if (retvalStruct) { + if (retvalStruct != retvalOrig) { + retval = CefV8ValueCppToC::Unwrap(retvalStruct); + } + } else { + retval = NULL; + } + + // Return type: bool + return _retval?true:false; +} + +bool CefV8InterceptorCToCpp::Set(const CefString& name, + const CefRefPtr object, const CefRefPtr value, + CefString& exception) { + cef_v8interceptor_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, set_byname)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: name; type: string_byref_const + DCHECK(!name.empty()); + if (name.empty()) + return false; + // Verify param: object; type: refptr_diff + DCHECK(object.get()); + if (!object.get()) + return false; + // Verify param: value; type: refptr_diff + DCHECK(value.get()); + if (!value.get()) + return false; + + // Execute + int _retval = _struct->set_byname(_struct, + name.GetStruct(), + CefV8ValueCppToC::Wrap(object), + CefV8ValueCppToC::Wrap(value), + exception.GetWritableStruct()); + + // Return type: bool + return _retval?true:false; +} + +bool CefV8InterceptorCToCpp::Set(int index, const CefRefPtr object, + const CefRefPtr value, CefString& exception) { + cef_v8interceptor_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, set_byindex)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: index; type: simple_byval + DCHECK_GE(index, 0); + if (index < 0) + return false; + // Verify param: object; type: refptr_diff + DCHECK(object.get()); + if (!object.get()) + return false; + // Verify param: value; type: refptr_diff + DCHECK(value.get()); + if (!value.get()) + return false; + + // Execute + int _retval = _struct->set_byindex(_struct, + index, + CefV8ValueCppToC::Wrap(object), + CefV8ValueCppToC::Wrap(value), + exception.GetWritableStruct()); + + // Return type: bool + return _retval?true:false; +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefV8InterceptorCToCpp::CefV8InterceptorCToCpp() { +} + +template<> cef_v8interceptor_t* CefCToCpp::UnwrapDerived(CefWrapperType type, + CefV8Interceptor* c) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template<> base::AtomicRefCount CefCToCpp::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCToCpp::kWrapperType = WT_V8INTERCEPTOR; diff --git a/libcef_dll/ctocpp/v8interceptor_ctocpp.h b/libcef_dll/ctocpp/v8interceptor_ctocpp.h new file mode 100644 index 000000000..1b70b825a --- /dev/null +++ b/libcef_dll/ctocpp/v8interceptor_ctocpp.h @@ -0,0 +1,45 @@ +// Copyright (c) 2016 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. +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_V8INTERCEPTOR_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_V8INTERCEPTOR_CTOCPP_H_ +#pragma once + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef_v8.h" +#include "include/capi/cef_v8_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefV8InterceptorCToCpp + : public CefCToCpp { + public: + CefV8InterceptorCToCpp(); + + // CefV8Interceptor methods. + bool Get(const CefString& name, const CefRefPtr object, + CefRefPtr& retval, CefString& exception) override; + bool Get(int index, const CefRefPtr object, + CefRefPtr& retval, CefString& exception) override; + bool Set(const CefString& name, const CefRefPtr object, + const CefRefPtr value, CefString& exception) override; + bool Set(int index, const CefRefPtr object, + const CefRefPtr value, CefString& exception) override; +}; + +#endif // BUILDING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CTOCPP_V8INTERCEPTOR_CTOCPP_H_ diff --git a/libcef_dll/ctocpp/v8value_ctocpp.cc b/libcef_dll/ctocpp/v8value_ctocpp.cc index 80538b004..62d50d278 100644 --- a/libcef_dll/ctocpp/v8value_ctocpp.cc +++ b/libcef_dll/ctocpp/v8value_ctocpp.cc @@ -13,6 +13,7 @@ #include "libcef_dll/cpptoc/base_cpptoc.h" #include "libcef_dll/cpptoc/v8accessor_cpptoc.h" #include "libcef_dll/cpptoc/v8handler_cpptoc.h" +#include "libcef_dll/cpptoc/v8interceptor_cpptoc.h" #include "libcef_dll/ctocpp/v8context_ctocpp.h" #include "libcef_dll/ctocpp/v8exception_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" @@ -110,14 +111,16 @@ CefRefPtr CefV8Value::CreateString(const CefString& value) { } CefRefPtr CefV8Value::CreateObject( - CefRefPtr accessor) { + CefRefPtr accessor, + CefRefPtr interceptor) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING - // Unverified params: accessor + // Unverified params: accessor, interceptor // Execute cef_v8value_t* _retval = cef_v8value_create_object( - CefV8AccessorCppToC::Wrap(accessor)); + CefV8AccessorCppToC::Wrap(accessor), + CefV8InterceptorCppToC::Wrap(interceptor)); // Return type: refptr_same return CefV8ValueCToCpp::Wrap(_retval); diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 208333cb6..2478fc2a9 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -140,6 +140,7 @@ #include "libcef_dll/ctocpp/urlrequest_client_ctocpp.h" #include "libcef_dll/ctocpp/v8accessor_ctocpp.h" #include "libcef_dll/ctocpp/v8handler_ctocpp.h" +#include "libcef_dll/ctocpp/v8interceptor_ctocpp.h" #include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h" #include "libcef_dll/ctocpp/web_plugin_info_visitor_ctocpp.h" #include "libcef_dll/ctocpp/web_plugin_unstable_callback_ctocpp.h" @@ -323,6 +324,7 @@ CEF_EXPORT void cef_shutdown() { DCHECK(base::AtomicRefCountIsZero(&CefV8ContextCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ExceptionCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8HandlerCToCpp::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero(&CefV8InterceptorCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8StackFrameCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8StackTraceCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ValueCppToC::DebugObjCt)); diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 248a285e1..189d7f6c8 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -82,6 +82,7 @@ #include "libcef_dll/cpptoc/urlrequest_client_cpptoc.h" #include "libcef_dll/cpptoc/v8accessor_cpptoc.h" #include "libcef_dll/cpptoc/v8handler_cpptoc.h" +#include "libcef_dll/cpptoc/v8interceptor_cpptoc.h" #include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h" #include "libcef_dll/cpptoc/web_plugin_info_visitor_cpptoc.h" #include "libcef_dll/cpptoc/web_plugin_unstable_callback_cpptoc.h" @@ -315,6 +316,7 @@ CEF_GLOBAL void CefShutdown() { DCHECK(base::AtomicRefCountIsZero(&CefV8ContextCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ExceptionCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8HandlerCppToC::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero(&CefV8InterceptorCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8StackFrameCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8StackTraceCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefV8ValueCToCpp::DebugObjCt)); diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index 76ad2965d..12531300e 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -126,6 +126,7 @@ enum CefWrapperType { WT_V8CONTEXT, WT_V8EXCEPTION, WT_V8HANDLER, + WT_V8INTERCEPTOR, WT_V8STACK_FRAME, WT_V8STACK_TRACE, WT_V8VALUE, diff --git a/tests/cefclient/renderer/performance_test.cc b/tests/cefclient/renderer/performance_test.cc index 7cc5736d6..02d5f4c5e 100644 --- a/tests/cefclient/renderer/performance_test.cc +++ b/tests/cefclient/renderer/performance_test.cc @@ -104,7 +104,7 @@ class V8Handler : public CefV8Handler { retval = CefV8Value::CreateString("Hello, world!"); break; case 8: - retval = CefV8Value::CreateObject(NULL); + retval = CefV8Value::CreateObject(NULL, NULL); break; case 9: retval = CefV8Value::CreateArray(8); diff --git a/tests/cefclient/renderer/performance_test_tests.cc b/tests/cefclient/renderer/performance_test_tests.cc index ccd387b5f..b63b5939a 100644 --- a/tests/cefclient/renderer/performance_test_tests.cc +++ b/tests/cefclient/renderer/performance_test_tests.cc @@ -154,7 +154,7 @@ PERF_TEST_FUNC(V8FunctionExecuteWithContext) { PERF_TEST_FUNC(V8ObjectCreate) { PERF_ITERATIONS_START() - CefRefPtr value = CefV8Value::CreateObject(NULL); + CefRefPtr value = CefV8Value::CreateObject(NULL, NULL); PERF_ITERATIONS_END() } @@ -180,15 +180,53 @@ PERF_TEST_FUNC(V8ObjectCreateWithAccessor) { CefRefPtr accessor = new Accessor(); PERF_ITERATIONS_START() - CefRefPtr value = CefV8Value::CreateObject(accessor); + CefRefPtr value = CefV8Value::CreateObject(accessor, NULL); PERF_ITERATIONS_END() } +PERF_TEST_FUNC(V8ObjectCreateWithInterceptor) { + class Interceptor : public CefV8Interceptor { + public: + Interceptor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + return true; + } + virtual bool Get(int index, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + return true; + } + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + return true; + } + virtual bool Set(int index, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + return true; + } + IMPLEMENT_REFCOUNTING(Interceptor); + }; + + CefRefPtr interceptor = new Interceptor(); + + PERF_ITERATIONS_START() + CefRefPtr value = CefV8Value::CreateObject(NULL, + interceptor); + PERF_ITERATIONS_END() +} PERF_TEST_FUNC(V8ObjectSetValue) { CefString name = "name"; CefRefPtr val = CefV8Value::CreateBool(true); - CefRefPtr obj = CefV8Value::CreateObject(NULL); + CefRefPtr obj = CefV8Value::CreateObject(NULL, NULL); obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE); PERF_ITERATIONS_START() @@ -199,7 +237,7 @@ PERF_TEST_FUNC(V8ObjectSetValue) { PERF_TEST_FUNC(V8ObjectGetValue) { CefString name = "name"; CefRefPtr val = CefV8Value::CreateBool(true); - CefRefPtr obj = CefV8Value::CreateObject(NULL); + CefRefPtr obj = CefV8Value::CreateObject(NULL, NULL); obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE); PERF_ITERATIONS_START() @@ -232,7 +270,7 @@ PERF_TEST_FUNC(V8ObjectSetValueWithAccessor) { CefString name = "name"; CefRefPtr val = CefV8Value::CreateBool(true); - CefRefPtr obj = CefV8Value::CreateObject(accessor); + CefRefPtr obj = CefV8Value::CreateObject(accessor, NULL); obj->SetValue(name, V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE); obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE); @@ -266,7 +304,7 @@ PERF_TEST_FUNC(V8ObjectGetValueWithAccessor) { CefString name = "name"; CefRefPtr val = CefV8Value::CreateBool(true); - CefRefPtr obj = CefV8Value::CreateObject(accessor); + CefRefPtr obj = CefV8Value::CreateObject(accessor, NULL); obj->SetValue(name, V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE); obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE); @@ -316,6 +354,7 @@ const PerfTestEntry kPerfTests[] = { PERF_TEST_ENTRY(V8FunctionExecuteWithContext), PERF_TEST_ENTRY(V8ObjectCreate), PERF_TEST_ENTRY(V8ObjectCreateWithAccessor), + PERF_TEST_ENTRY(V8ObjectCreateWithInterceptor), PERF_TEST_ENTRY(V8ObjectSetValue), PERF_TEST_ENTRY(V8ObjectGetValue), PERF_TEST_ENTRY(V8ObjectSetValueWithAccessor), diff --git a/tests/unittests/v8_unittest.cc b/tests/unittests/v8_unittest.cc index 1b9314d0c..88b8124e4 100644 --- a/tests/unittests/v8_unittest.cc +++ b/tests/unittests/v8_unittest.cc @@ -59,6 +59,10 @@ enum V8TestMode { V8TEST_OBJECT_ACCESSOR_EXCEPTION, V8TEST_OBJECT_ACCESSOR_FAIL, V8TEST_OBJECT_ACCESSOR_READONLY, + V8TEST_OBJECT_INTERCEPTOR, + V8TEST_OBJECT_INTERCEPTOR_FAIL, + V8TEST_OBJECT_INTERCEPTOR_EXCEPTION, + V8TEST_OBJECT_INTERCEPTOR_AND_ACCESSOR, V8TEST_OBJECT_VALUE, V8TEST_OBJECT_VALUE_READONLY, V8TEST_OBJECT_VALUE_ENUM, @@ -171,6 +175,18 @@ class V8RendererTest : public ClientAppRenderer::Delegate, case V8TEST_OBJECT_ACCESSOR_READONLY: RunObjectAccessorReadOnlyTest(); break; + case V8TEST_OBJECT_INTERCEPTOR: + RunObjectInterceptorTest(); + break; + case V8TEST_OBJECT_INTERCEPTOR_FAIL: + RunObjectInterceptorFailTest(); + break; + case V8TEST_OBJECT_INTERCEPTOR_EXCEPTION: + RunObjectInterceptorExceptionTest(); + break; + case V8TEST_OBJECT_INTERCEPTOR_AND_ACCESSOR: + RunObjectInterceptorAndAccessorTest(); + break; case V8TEST_OBJECT_VALUE: RunObjectValueTest(); break; @@ -529,7 +545,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, // Enter the V8 context. EXPECT_TRUE(context->Enter()); - CefRefPtr value = CefV8Value::CreateObject(NULL); + CefRefPtr value = CefV8Value::CreateObject(NULL, NULL); EXPECT_TRUE(value.get()); EXPECT_TRUE(value->IsObject()); @@ -565,7 +581,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, // Enter the V8 context. EXPECT_TRUE(context->Enter()); - CefRefPtr value = CefV8Value::CreateObject(NULL); + CefRefPtr value = CefV8Value::CreateObject(NULL, NULL); EXPECT_TRUE(value.get()); EXPECT_TRUE(value->SetUserData(new UserData(10))); @@ -640,7 +656,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, Accessor* accessor = new Accessor; CefRefPtr accessorPtr(accessor); - CefRefPtr object = CefV8Value::CreateObject(accessor); + CefRefPtr object = CefV8Value::CreateObject(accessor, NULL); EXPECT_TRUE(object.get()); accessor->object_ = object; @@ -715,7 +731,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, Accessor* accessor = new Accessor; CefRefPtr accessorPtr(accessor); - CefRefPtr object = CefV8Value::CreateObject(accessor); + CefRefPtr object = CefV8Value::CreateObject(accessor, NULL); EXPECT_TRUE(object.get()); EXPECT_FALSE(object->HasValue(kName)); @@ -787,7 +803,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, Accessor* accessor = new Accessor; CefRefPtr accessorPtr(accessor); - CefRefPtr object = CefV8Value::CreateObject(accessor); + CefRefPtr object = CefV8Value::CreateObject(accessor, NULL); EXPECT_TRUE(object.get()); EXPECT_FALSE(object->HasValue(kName)); @@ -851,7 +867,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, Accessor* accessor = new Accessor; CefRefPtr accessorPtr(accessor); - CefRefPtr object = CefV8Value::CreateObject(accessor); + CefRefPtr object = CefV8Value::CreateObject(accessor, NULL); EXPECT_TRUE(object.get()); EXPECT_FALSE(object->HasValue(kName)); @@ -878,6 +894,613 @@ class V8RendererTest : public ClientAppRenderer::Delegate, DestroyTest(); } + void RunObjectInterceptorTest() { + CefRefPtr context = GetContext(); + + static const char* kName1 = "val1"; + static const char* kName2 = "val2"; + static const char* kName3 = "val3"; + + static const int kValue1 = 20; + static const uint32 kValue2 = 30u; + static const char* kValue3 = "40"; + + static const int kArray[] = {50, 60, 70}; + + class Interceptor : public CefV8Interceptor { + public: + Interceptor() : value1_(0), value2_(0u), array_() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + EXPECT_TRUE(name.ToString() == kName1 || + name.ToString() == kName2 || + name.ToString() == kName3); + + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->IsSame(object_)); + + EXPECT_FALSE(retval.get()); + EXPECT_TRUE(exception.empty()); + + got_get_byname_.yes(); + if (name.ToString() == kName1) { + retval = CefV8Value::CreateInt(value1_); + EXPECT_EQ(kValue1, retval->GetIntValue()); + } else if (name.ToString() == kName2) { + retval = CefV8Value::CreateUInt(value2_); + EXPECT_EQ(kValue2, retval->GetUIntValue()); + } else if (name.ToString() == kName3) { + retval = CefV8Value::CreateString(value3_); + EXPECT_STREQ(kValue3, retval->GetStringValue().ToString().c_str()); + } + return true; + } + + virtual bool Get(int index, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + EXPECT_TRUE(index >= 0 && index < 3); + + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->IsSame(object_)); + + EXPECT_FALSE(retval.get()); + EXPECT_TRUE(exception.empty()); + + got_get_byindex_.yes(); + retval = CefV8Value::CreateInt(array_[index]); + EXPECT_EQ(kArray[index], retval->GetIntValue()); + return true; + } + + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + EXPECT_TRUE(name.ToString() == kName1 || + name.ToString() == kName2 || + name.ToString() == kName3); + + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->IsSame(object_)); + + EXPECT_TRUE(value.get()); + EXPECT_TRUE(exception.empty()); + + got_set_byname_.yes(); + if (name.ToString() == kName1) { + value1_ = value->GetIntValue(); + EXPECT_EQ(kValue1, value1_); + } else if (name.ToString() == kName2) { + value2_ = value->GetUIntValue(); + EXPECT_EQ(kValue2, value2_); + } else if (name.ToString() == kName3) { + value3_ = value->GetStringValue(); + EXPECT_STREQ(kValue3, value3_.ToString().c_str()); + } + return true; + } + + virtual bool Set(int index, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + EXPECT_TRUE(index >= 0 && index < 3); + + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->IsSame(object_)); + + EXPECT_TRUE(value.get()); + EXPECT_TRUE(exception.empty()); + + got_set_byindex_.yes(); + array_[index] = value->GetIntValue(); + EXPECT_EQ(array_[index], kArray[index]); + return true; + } + + CefRefPtr object_; + int value1_; + unsigned int value2_; + CefString value3_; + int array_[3]; + + TrackCallback got_get_byname_; + TrackCallback got_get_byindex_; + TrackCallback got_set_byname_; + TrackCallback got_set_byindex_; + + IMPLEMENT_REFCOUNTING(Interceptor); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Interceptor* interceptor = new Interceptor; + CefRefPtr interceptorPtr(interceptor); + + CefRefPtr object = CefV8Value::CreateObject(NULL, interceptor); + EXPECT_TRUE(object.get()); + interceptor->object_ = object; + + EXPECT_FALSE(object->HasException()); + + EXPECT_TRUE(object->SetValue(kName1, CefV8Value::CreateInt(kValue1), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byname_); + interceptor->got_set_byname_.reset(); + + EXPECT_TRUE(object->SetValue(kName2, CefV8Value::CreateUInt(kValue2), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byname_); + interceptor->got_set_byname_.reset(); + + EXPECT_TRUE(object->SetValue(kName3, CefV8Value::CreateString(kValue3), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byname_); + interceptor->got_set_byname_.reset(); + + EXPECT_EQ(kValue1, interceptor->value1_); + EXPECT_EQ(kValue2, interceptor->value2_); + EXPECT_STREQ(kValue3, interceptor->value3_.ToString().c_str()); + + for (int i=0; i<3; ++i) { + EXPECT_TRUE(object->SetValue(i, CefV8Value::CreateInt(kArray[i]))); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byindex_); + interceptor->got_set_byindex_.reset(); + EXPECT_EQ(kArray[i], interceptor->array_[i]); + } + + CefRefPtr val1 = object->GetValue(kName1); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(val1.get()); + EXPECT_TRUE(interceptor->got_get_byname_); + interceptor->got_get_byname_.reset(); + EXPECT_TRUE(val1->IsInt()); + EXPECT_EQ(kValue1, val1->GetIntValue()); + + CefRefPtr val2 = object->GetValue(kName2); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(val2.get()); + EXPECT_TRUE(interceptor->got_get_byname_); + interceptor->got_get_byname_.reset(); + EXPECT_TRUE(val2->IsUInt()); + EXPECT_EQ(kValue2, val2->GetUIntValue()); + + CefRefPtr val3 = object->GetValue(kName3); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(val3.get()); + EXPECT_TRUE(interceptor->got_get_byname_); + interceptor->got_get_byname_.reset(); + EXPECT_TRUE(val3->IsString()); + EXPECT_STREQ(kValue3, val3->GetStringValue().ToString().c_str()); + + for (int i=0; i<3; ++i) { + CefRefPtr val = object->GetValue(i); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(val.get()); + EXPECT_TRUE(interceptor->got_get_byindex_); + interceptor->got_get_byname_.reset(); + EXPECT_EQ(kArray[i], val->GetIntValue()); + } + + interceptor->object_ = NULL; + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectInterceptorFailTest() { + CefRefPtr context = GetContext(); + + static const char* kName = "val"; + static const int kIndex = 0; + static const int kValue1 = 20; + static const int kValue2 = 30; + + class Interceptor : public CefV8Interceptor { + typedef std::map IntMap; + typedef std::map StringMap; + public: + Interceptor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_byname_.yes(); + StringMap::iterator it = string_map_.find(name.ToString()); + if(it != string_map_.end()) { + retval = CefV8Value::CreateInt(it->second); + } + return true; + } + + virtual bool Get(int index, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_byindex_.yes(); + IntMap::iterator it = int_map_.find(index); + if(it != int_map_.end()) { + retval = CefV8Value::CreateInt(it->second); + } + return true; + } + + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + EXPECT_TRUE(value->IsInt()); + got_set_byname_.yes(); + string_map_[name.ToString()] = value->GetIntValue(); + return true; + } + + virtual bool Set(int index, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + EXPECT_TRUE(value->IsInt()); + got_set_byindex_.yes(); + int_map_[index] = value->GetIntValue(); + return true; + } + + IntMap int_map_; + StringMap string_map_; + + TrackCallback got_get_byname_; + TrackCallback got_get_byindex_; + TrackCallback got_set_byname_; + TrackCallback got_set_byindex_; + + IMPLEMENT_REFCOUNTING(Interceptor); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Interceptor* interceptor = new Interceptor; + CefRefPtr interceptorPtr(interceptor); + + CefRefPtr object = CefV8Value::CreateObject(NULL, interceptor); + EXPECT_TRUE(object.get()); + + EXPECT_FALSE(object->HasValue(kName)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byname_); + interceptor->got_get_byname_.reset(); + + CefRefPtr val1 = object->GetValue(kName); + EXPECT_TRUE(val1.get()); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byname_); + EXPECT_TRUE(val1->IsUndefined()); + interceptor->got_get_byname_.reset(); + + EXPECT_TRUE(object->SetValue( + kName, + CefV8Value::CreateInt(kValue1), V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byname_); + + val1 = object->GetValue(kName); + EXPECT_TRUE(val1.get()); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byname_); + EXPECT_EQ(kValue1, val1->GetIntValue()); + + EXPECT_FALSE(object->HasValue(kIndex)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byindex_); + interceptor->got_get_byindex_.reset(); + + CefRefPtr val2 = object->GetValue(kIndex); + EXPECT_TRUE(val2.get()); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byindex_); + EXPECT_TRUE(val2->IsUndefined()); + interceptor->got_get_byindex_.reset(); + + EXPECT_TRUE(object->SetValue(kIndex, CefV8Value::CreateInt(kValue2))); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byindex_); + + val2 = object->GetValue(kIndex); + EXPECT_TRUE(val2.get()); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byindex_); + EXPECT_EQ(kValue2, val2->GetIntValue()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectInterceptorExceptionTest() { + CefRefPtr context = GetContext(); + static const char* kName = "val"; + static const int kIndex = 1; + + static const char* kGetByNameException = "My get_byname exception"; + static const char* kGetByIndexException = "My get_byindex exception"; + static const char* kSetByNameException = "My set_byname exception"; + static const char* kSetByIndexException = "My set_byindex exception"; + + static const char* kGetByNameExceptionMsg = + "Uncaught Error: My get_byname exception"; + static const char* kGetByIndexExceptionMsg = + "Uncaught Error: My get_byindex exception"; + static const char* kSetByNameExceptionMsg = + "Uncaught Error: My set_byname exception"; + static const char* kSetByIndexExceptionMsg = + "Uncaught Error: My set_byindex exception"; + + class Interceptor : public CefV8Interceptor { + public: + Interceptor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_byname_.yes(); + exception = kGetByNameException; + return true; + } + + virtual bool Get(int index, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_byindex_.yes(); + exception = kGetByIndexException; + return true; + } + + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_byname_.yes(); + exception = kSetByNameException; + return true; + } + + virtual bool Set(int index, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_byindex_.yes(); + exception = kSetByIndexException; + return true; + } + + TrackCallback got_get_byname_; + TrackCallback got_get_byindex_; + TrackCallback got_set_byname_; + TrackCallback got_set_byindex_; + + IMPLEMENT_REFCOUNTING(Interceptor); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr exception; + Interceptor* interceptor = new Interceptor; + CefRefPtr interceptorPtr(interceptor); + + CefRefPtr object = CefV8Value::CreateObject(NULL, + interceptor); + EXPECT_TRUE(object.get()); + + EXPECT_FALSE(object->SetValue(kName, CefV8Value::CreateInt(1), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_TRUE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byname_); + exception = object->GetException(); + EXPECT_TRUE(exception.get()); + EXPECT_STREQ(kSetByNameExceptionMsg, + exception->GetMessage().ToString().c_str()); + + EXPECT_TRUE(object->ClearException()); + EXPECT_FALSE(object->HasException()); + + CefRefPtr val1 = object->GetValue(kName); + EXPECT_FALSE(val1.get()); + EXPECT_TRUE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byname_); + exception = object->GetException(); + EXPECT_TRUE(exception.get()); + EXPECT_STREQ(kGetByNameExceptionMsg, + exception->GetMessage().ToString().c_str()); + + EXPECT_TRUE(object->ClearException()); + EXPECT_FALSE(object->HasException()); + + EXPECT_FALSE(object->SetValue(kIndex, CefV8Value::CreateInt(1))); + EXPECT_TRUE(object->HasException()); + EXPECT_TRUE(interceptor->got_set_byindex_); + exception = object->GetException(); + EXPECT_TRUE(exception.get()); + EXPECT_STREQ(kSetByIndexExceptionMsg, + exception->GetMessage().ToString().c_str()); + + EXPECT_TRUE(object->ClearException()); + EXPECT_FALSE(object->HasException()); + + CefRefPtr val2 = object->GetValue(kIndex); + EXPECT_FALSE(val2.get()); + EXPECT_TRUE(object->HasException()); + EXPECT_TRUE(interceptor->got_get_byindex_); + exception = object->GetException(); + EXPECT_TRUE(exception.get()); + EXPECT_STREQ(kGetByIndexExceptionMsg, + exception->GetMessage().ToString().c_str()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectInterceptorAndAccessorTest() { + CefRefPtr context = GetContext(); + static const char* kInterceptorName = "val1"; + static const char* kAccessorName = "val2"; + + static const int kInterceptorValue = 20; + static const int kAccessorValue = 30; + + class Interceptor : public CefV8Interceptor { + public: + Interceptor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + EXPECT_FALSE(retval.get()); + got_get_byname_.yes(); + if (name.ToString() == kInterceptorName) { + retval = CefV8Value::CreateInt(kInterceptorValue); + } + return true; + } + + virtual bool Get(int index, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_byindex_.yes(); + return true; + } + + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_byname_.yes(); + return true; + } + + virtual bool Set(int index, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_byindex_.yes(); + return true; + } + + TrackCallback got_get_byname_; + TrackCallback got_get_byindex_; + TrackCallback got_set_byname_; + TrackCallback got_set_byindex_; + + IMPLEMENT_REFCOUNTING(Interceptor); + }; + + class Accessor : public CefV8Accessor { + public: + Accessor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_.yes(); + retval = CefV8Value::CreateInt(kAccessorValue); + return true; + } + + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_.yes(); + return true; + } + + TrackCallback got_get_; + TrackCallback got_set_; + + IMPLEMENT_REFCOUNTING(Accessor); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Interceptor* interceptor = new Interceptor; + CefRefPtr interceptorPtr(interceptor); + + Accessor* accessor = new Accessor; + CefRefPtr accessorPtr(accessor); + + CefRefPtr object = CefV8Value::CreateObject( + accessor, interceptor); + EXPECT_TRUE(object.get()); + + // We register both names for accessor. + EXPECT_TRUE(object->SetValue(kAccessorName, V8_ACCESS_CONTROL_DEFAULT, + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + + EXPECT_TRUE(object->SetValue(kInterceptorName, V8_ACCESS_CONTROL_DEFAULT, + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + + EXPECT_TRUE(object->SetValue(kAccessorName, + CefV8Value::CreateInt(kAccessorValue), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(accessor->got_set_); + accessor->got_set_.reset(); + EXPECT_TRUE(interceptor->got_set_byname_); + interceptor->got_set_byname_.reset(); + + EXPECT_TRUE(object->SetValue(kInterceptorName, + CefV8Value::CreateInt(kInterceptorValue), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(object->HasException()); + EXPECT_TRUE(accessor->got_set_); + accessor->got_set_.reset(); + EXPECT_TRUE(interceptor->got_set_byname_); + interceptor->got_set_byname_.reset(); + + // When interceptor returns nothing, accessor's getter is called. + CefRefPtr val1 = object->GetValue(kAccessorName); + EXPECT_TRUE(val1.get()); + EXPECT_TRUE(interceptor->got_get_byname_); + interceptor->got_get_byname_.reset(); + EXPECT_TRUE(accessor->got_get_); + accessor->got_get_.reset(); + EXPECT_EQ(kAccessorValue, val1->GetIntValue()); + + // When interceptor returns value, accessor's getter is not called. + CefRefPtr val2 = object->GetValue(kInterceptorName); + EXPECT_TRUE(val2.get()); + EXPECT_TRUE(interceptor->got_get_byname_); + EXPECT_FALSE(accessor->got_get_); + EXPECT_EQ(kInterceptorValue, val2->GetIntValue()); + + EXPECT_FALSE(interceptor->got_get_byindex_); + EXPECT_FALSE(interceptor->got_set_byindex_); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + void RunObjectValueTest() { CefRefPtr context = GetContext(); @@ -968,7 +1591,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, CefRefPtr object = context->GetGlobal(); EXPECT_TRUE(object.get()); - CefRefPtr obj1 = CefV8Value::CreateObject(NULL); + CefRefPtr obj1 = CefV8Value::CreateObject(NULL, NULL); object->SetValue(kObjName, obj1, V8_PROPERTY_ATTRIBUTE_NONE); obj1->SetValue(kArgName, CefV8Value::CreateInt(0), @@ -1010,7 +1633,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, CefRefPtr object = context->GetGlobal(); EXPECT_TRUE(object.get()); - CefRefPtr obj1 = CefV8Value::CreateObject(NULL); + CefRefPtr obj1 = CefV8Value::CreateObject(NULL, NULL); object->SetValue(kObjName, obj1, V8_PROPERTY_ATTRIBUTE_NONE); obj1->SetValue(kArgName, CefV8Value::CreateInt(0), @@ -1242,7 +1865,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate, CefV8Value::CreateFunction(kFuncName, handler); EXPECT_TRUE(func.get()); - CefRefPtr obj = CefV8Value::CreateObject(NULL); + CefRefPtr obj = CefV8Value::CreateObject(NULL, NULL); EXPECT_TRUE(obj.get()); handler->object_ = obj; @@ -2230,6 +2853,11 @@ V8_TEST(ObjectAccessor, V8TEST_OBJECT_ACCESSOR); V8_TEST(ObjectAccessorException, V8TEST_OBJECT_ACCESSOR_EXCEPTION); V8_TEST(ObjectAccessorFail, V8TEST_OBJECT_ACCESSOR_FAIL); V8_TEST(ObjectAccessorReadOnly, V8TEST_OBJECT_ACCESSOR_READONLY); +V8_TEST(RunObjectInterceptorTest, V8TEST_OBJECT_INTERCEPTOR); +V8_TEST(RunObjectInterceptorFailTest, V8TEST_OBJECT_INTERCEPTOR_FAIL); +V8_TEST(RunObjectInterceptorExceptionTest, V8TEST_OBJECT_INTERCEPTOR_EXCEPTION); +V8_TEST(RunObjectInterceptorAndAccessorTest, + V8TEST_OBJECT_INTERCEPTOR_AND_ACCESSOR); V8_TEST(ObjectValue, V8TEST_OBJECT_VALUE); V8_TEST(ObjectValueReadOnly, V8TEST_OBJECT_VALUE_READONLY); V8_TEST(ObjectValueEnum, V8TEST_OBJECT_VALUE_ENUM);