// Copyright (c) 2017 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. #ifndef CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_ #define CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_ #pragma once #include "include/base/cef_logging.h" #include "include/base/cef_macros.h" #include "include/capi/cef_base_capi.h" #include "include/cef_base.h" #include "libcef_dll/ptr_util.h" #include "libcef_dll/wrapper_types.h" // Wrap a C structure with a C++ class. This is used when the implementation // exists on the other side of the DLL boundary but will have methods called on // this side of the DLL boundary. template class CefCToCppScoped : public BaseName { public: // Create a new wrapper instance for a structure reference received from the // other side. The caller owns the CToCpp wrapper instance but not necessarily // the underling object on the CppToC side (depends if s->del is non-NULL). // The returned wrapper object can be used as either a scoped argument or to // pass ownership. For example: // // void my_method(my_type1_t* struct1, my_type2_t* struct2) { // // Passes ownership to MyMethod1(). // MyMethod1(MyType1CToCpp::Wrap(struct1)); // // // Passes reference to MyMethod2(). // CefOwnPtr obj2 = MyType2CToCpp::Wrap(struct2); // MyMethod2(obj2.get()); // // |obj2| is deleted when my_method() goes out of scope. // } // // void MyMethod1(CefOwnPtr obj1) { // // |obj1| is deleted when MyMethod1() goes out of scope. // } // // void MyMethod2(CefRawPtr obj2) { // } static CefOwnPtr Wrap(StructName* s); // Retrieve the underlying structure reference from a wrapper instance for // return back to the other side. Ownership will be passed back to the other // side and the wrapper will be deleted. For example: // // void MyMethod(CefOwnPtr obj) { // // Ownership of the underlying MyType object is passed to my_method(). // my_method(MyTypeCToCpp::UnwrapOwn(obj.Pass())); // // |obj| is now NULL. // } static StructName* UnwrapOwn(CefOwnPtr c); // Retrieve the underlying structure reference from a wrapper instance for // return back to the other side. Ownership does not change. For example: // // void MyMethod(CefRawPtr obj) { // // A reference is passed to my_method(). Ownership does not change. // my_method2(MyTypeCToCpp::UnwrapRaw(obj)); // } static StructName* UnwrapRaw(CefRawPtr c); // Override delete operator to properly delete the WrapperStruct. // ~CefCToCppScoped will be called first followed by this method. static void operator delete(void* ptr); #if DCHECK_IS_ON() // Simple tracking of allocated objects. static base::AtomicRefCount DebugObjCt; #endif protected: CefCToCppScoped() { #if DCHECK_IS_ON() base::AtomicRefCountInc(&DebugObjCt); #endif } virtual ~CefCToCppScoped() { #if DCHECK_IS_ON() base::AtomicRefCountDec(&DebugObjCt); #endif } // If returning the structure across the DLL boundary use Unwrap() instead. StructName* GetStruct() const { WrapperStruct* wrapperStruct = GetWrapperStruct(this); // Verify that the wrapper offset was calculated correctly. DCHECK_EQ(kWrapperType, wrapperStruct->type_); return wrapperStruct->struct_; } private: // Used to associate this wrapper object and the structure reference received // from the other side. struct WrapperStruct; static WrapperStruct* GetWrapperStruct(const BaseName* obj); // Unwrap as the derived type. static StructName* UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr c); static StructName* UnwrapDerivedRaw(CefWrapperType type, CefRawPtr c); static CefWrapperType kWrapperType; DISALLOW_COPY_AND_ASSIGN(CefCToCppScoped); }; template struct CefCToCppScoped::WrapperStruct { CefWrapperType type_; StructName* struct_; ClassName wrapper_; }; template CefOwnPtr CefCToCppScoped::Wrap( StructName* s) { if (!s) return CefOwnPtr(); // Wrap their structure with the CefCToCpp object. WrapperStruct* wrapperStruct = new WrapperStruct; wrapperStruct->type_ = kWrapperType; wrapperStruct->struct_ = s; return CefOwnPtr(&wrapperStruct->wrapper_); } template StructName* CefCToCppScoped::UnwrapOwn( CefOwnPtr c) { if (!c.get()) return NULL; WrapperStruct* wrapperStruct = GetWrapperStruct(c.get()); // If the type does not match this object then we need to unwrap as the // derived type. if (wrapperStruct->type_ != kWrapperType) return UnwrapDerivedOwn(wrapperStruct->type_, OWN_PASS(c)); StructName* orig_struct = wrapperStruct->struct_; #if DCHECK_IS_ON() // We should own the object currently. cef_base_scoped_t* base = reinterpret_cast(orig_struct); DCHECK(base && base->del); #endif // Don't delete the original object when the wrapper is deleted. wrapperStruct->struct_ = NULL; // Return the original structure. return orig_struct; // The wrapper |c| is deleted when this method goes out of scope. } template StructName* CefCToCppScoped::UnwrapRaw( CefRawPtr c) { if (!c) return NULL; WrapperStruct* wrapperStruct = GetWrapperStruct(c); // If the type does not match this object then we need to unwrap as the // derived type. if (wrapperStruct->type_ != kWrapperType) return UnwrapDerivedRaw(wrapperStruct->type_, c); // Return the original structure. return wrapperStruct->struct_; } template void CefCToCppScoped::operator delete( void* ptr) { WrapperStruct* wrapperStruct = GetWrapperStruct(static_cast(ptr)); // Verify that the wrapper offset was calculated correctly. DCHECK_EQ(kWrapperType, wrapperStruct->type_); // May be NULL if UnwrapOwn() was called. cef_base_scoped_t* base = reinterpret_cast(wrapperStruct->struct_); // If we own the object (base->del != NULL) then notify the other side that // the object has been deleted. if (base && base->del) base->del(base); // Delete the wrapper structure without executing ~CefCToCppScoped() an // additional time. ::operator delete(wrapperStruct); } template typename CefCToCppScoped::WrapperStruct* CefCToCppScoped::GetWrapperStruct( const BaseName* obj) { // Offset using the WrapperStruct size instead of individual member sizes to // avoid problems due to platform/compiler differences in structure padding. return reinterpret_cast( reinterpret_cast(const_cast(obj)) - (sizeof(WrapperStruct) - sizeof(ClassName))); } #endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_