| // 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 ClassName, class BaseName, class StructName> |
| 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<MyType1> obj2 = MyType2CToCpp::Wrap(struct2); |
| // MyMethod2(obj2.get()); |
| // // |obj2| is deleted when my_method() goes out of scope. |
| // } |
| // |
| // void MyMethod1(CefOwnPtr<MyType1> obj1) { |
| // // |obj1| is deleted when MyMethod1() goes out of scope. |
| // } |
| // |
| // void MyMethod2(CefRawPtr<MyType2> obj2) { |
| // } |
| static CefOwnPtr<BaseName> 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<MyType> 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<BaseName> 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<MyType> obj) { |
| // // A reference is passed to my_method(). Ownership does not change. |
| // my_method2(MyTypeCToCpp::UnwrapRaw(obj)); |
| // } |
| static StructName* UnwrapRaw(CefRawPtr<BaseName> c); |
| |
| // Override delete operator to properly delete the WrapperStruct. |
| // ~CefCToCppScoped will be called first followed by this method. |
| static void operator delete(void* ptr); |
| |
| protected: |
| CefCToCppScoped() {} |
| virtual ~CefCToCppScoped() {} |
| |
| // 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<BaseName> c); |
| static StructName* UnwrapDerivedRaw(CefWrapperType type, |
| CefRawPtr<BaseName> c); |
| |
| static CefWrapperType kWrapperType; |
| |
| DISALLOW_COPY_AND_ASSIGN(CefCToCppScoped); |
| }; |
| |
| template <class ClassName, class BaseName, class StructName> |
| struct CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct { |
| CefWrapperType type_; |
| StructName* struct_; |
| ClassName wrapper_; |
| }; |
| |
| template <class ClassName, class BaseName, class StructName> |
| CefOwnPtr<BaseName> CefCToCppScoped<ClassName, BaseName, StructName>::Wrap( |
| StructName* s) { |
| if (!s) |
| return CefOwnPtr<BaseName>(); |
| |
| // Wrap their structure with the CefCToCpp object. |
| WrapperStruct* wrapperStruct = new WrapperStruct; |
| wrapperStruct->type_ = kWrapperType; |
| wrapperStruct->struct_ = s; |
| |
| return CefOwnPtr<BaseName>(&wrapperStruct->wrapper_); |
| } |
| |
| template <class ClassName, class BaseName, class StructName> |
| StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapOwn( |
| CefOwnPtr<BaseName> c) { |
| if (!c.get()) |
| return nullptr; |
| |
| 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<cef_base_scoped_t*>(orig_struct); |
| DCHECK(base && base->del); |
| #endif |
| |
| // Don't delete the original object when the wrapper is deleted. |
| wrapperStruct->struct_ = nullptr; |
| |
| // Return the original structure. |
| return orig_struct; |
| // The wrapper |c| is deleted when this method goes out of scope. |
| } |
| |
| template <class ClassName, class BaseName, class StructName> |
| StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapRaw( |
| CefRawPtr<BaseName> c) { |
| if (!c) |
| return nullptr; |
| |
| 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 <class ClassName, class BaseName, class StructName> |
| NO_SANITIZE("cfi-icall") |
| void CefCToCppScoped<ClassName, BaseName, StructName>::operator delete( |
| void* ptr) { |
| WrapperStruct* wrapperStruct = GetWrapperStruct(static_cast<BaseName*>(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<cef_base_scoped_t*>(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 <class ClassName, class BaseName, class StructName> |
| typename CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct* |
| CefCToCppScoped<ClassName, BaseName, StructName>::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<WrapperStruct*>( |
| reinterpret_cast<char*>(const_cast<BaseName*>(obj)) - |
| (sizeof(WrapperStruct) - sizeof(ClassName))); |
| } |
| |
| #endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_ |