| // Copyright (c) 2009 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_CPPTOC_CPPTOC_REF_COUNTED_H_ |
| #define CEF_LIBCEF_DLL_CPPTOC_CPPTOC_REF_COUNTED_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/wrapper_types.h" |
| |
| // Wrap a C++ class with a C structure. This is used when the class |
| // implementation exists on this side of the DLL boundary but will have methods |
| // called from the other side of the DLL boundary. |
| template <class ClassName, class BaseName, class StructName> |
| class CefCppToCRefCounted : public CefBaseRefCounted { |
| public: |
| // Create a new wrapper instance and associated structure reference for |
| // passing an object instance the other side. |
| static StructName* Wrap(CefRefPtr<BaseName> c) { |
| if (!c.get()) |
| return nullptr; |
| |
| // Wrap our object with the CefCppToCRefCounted class. |
| ClassName* wrapper = new ClassName(); |
| wrapper->wrapper_struct_.object_ = c.get(); |
| // Add a reference to our wrapper object that will be released once our |
| // structure arrives on the other side. |
| wrapper->AddRef(); |
| // Return the structure pointer that can now be passed to the other side. |
| return wrapper->GetStruct(); |
| } |
| |
| // Retrieve the underlying object instance for a structure reference passed |
| // back from the other side. |
| static CefRefPtr<BaseName> Unwrap(StructName* s) { |
| if (!s) |
| return nullptr; |
| |
| // Cast our structure to the wrapper structure type. |
| WrapperStruct* wrapperStruct = GetWrapperStruct(s); |
| |
| // If the type does not match this object then we need to unwrap as the |
| // derived type. |
| if (wrapperStruct->type_ != kWrapperType) |
| return UnwrapDerived(wrapperStruct->type_, s); |
| |
| // Add the underlying object instance to a smart pointer. |
| CefRefPtr<BaseName> objectPtr(wrapperStruct->object_); |
| // Release the reference to our wrapper object that was added before the |
| // structure was passed back to us. |
| wrapperStruct->wrapper_->Release(); |
| // Return the underlying object instance. |
| return objectPtr; |
| } |
| |
| // Retrieve the underlying object instance from our own structure reference |
| // when the reference is passed as the required first parameter of a C API |
| // function call. No explicit reference counting is done in this case. |
| static CefRefPtr<BaseName> Get(StructName* s) { |
| DCHECK(s); |
| WrapperStruct* wrapperStruct = GetWrapperStruct(s); |
| // Verify that the wrapper offset was calculated correctly. |
| DCHECK_EQ(kWrapperType, wrapperStruct->type_); |
| return wrapperStruct->object_; |
| } |
| |
| // If returning the structure across the DLL boundary you should call |
| // AddRef() on this CefCppToCRefCounted object. On the other side of the DLL |
| // boundary, call UnderlyingRelease() on the wrapping CefCToCpp object. |
| StructName* GetStruct() { return &wrapper_struct_.struct_; } |
| |
| // CefBaseRefCounted methods increment/decrement reference counts on both this |
| // object and the underlying wrapper class. |
| void AddRef() const { |
| UnderlyingAddRef(); |
| ref_count_.AddRef(); |
| } |
| bool Release() const { |
| UnderlyingRelease(); |
| if (ref_count_.Release()) { |
| delete this; |
| return true; |
| } |
| return false; |
| } |
| bool HasOneRef() const { return UnderlyingHasOneRef(); } |
| bool HasAtLeastOneRef() const { return UnderlyingHasAtLeastOneRef(); } |
| |
| protected: |
| CefCppToCRefCounted() { |
| wrapper_struct_.type_ = kWrapperType; |
| wrapper_struct_.wrapper_ = this; |
| memset(GetStruct(), 0, sizeof(StructName)); |
| |
| cef_base_ref_counted_t* base = |
| reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); |
| base->size = sizeof(StructName); |
| base->add_ref = struct_add_ref; |
| base->release = struct_release; |
| base->has_one_ref = struct_has_one_ref; |
| base->has_at_least_one_ref = struct_has_at_least_one_ref; |
| } |
| |
| virtual ~CefCppToCRefCounted() {} |
| |
| private: |
| // Used to associate this wrapper object, the underlying object instance and |
| // the structure that will be passed to the other side. |
| struct WrapperStruct { |
| CefWrapperType type_; |
| BaseName* object_; |
| CefCppToCRefCounted<ClassName, BaseName, StructName>* wrapper_; |
| StructName struct_; |
| }; |
| |
| static WrapperStruct* GetWrapperStruct(StructName* s) { |
| // 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*>(s) - |
| (sizeof(WrapperStruct) - sizeof(StructName))); |
| } |
| |
| // Unwrap as the derived type. |
| static CefRefPtr<BaseName> UnwrapDerived(CefWrapperType type, StructName* s); |
| |
| // Increment/decrement reference counts on only the underlying class. |
| void UnderlyingAddRef() const { wrapper_struct_.object_->AddRef(); } |
| void UnderlyingRelease() const { wrapper_struct_.object_->Release(); } |
| bool UnderlyingHasOneRef() const { |
| return wrapper_struct_.object_->HasOneRef(); |
| } |
| bool UnderlyingHasAtLeastOneRef() const { |
| return wrapper_struct_.object_->HasAtLeastOneRef(); |
| } |
| |
| static void CEF_CALLBACK struct_add_ref(cef_base_ref_counted_t* base) { |
| DCHECK(base); |
| if (!base) |
| return; |
| |
| WrapperStruct* wrapperStruct = |
| GetWrapperStruct(reinterpret_cast<StructName*>(base)); |
| // Verify that the wrapper offset was calculated correctly. |
| DCHECK_EQ(kWrapperType, wrapperStruct->type_); |
| |
| wrapperStruct->wrapper_->AddRef(); |
| } |
| |
| static int CEF_CALLBACK struct_release(cef_base_ref_counted_t* base) { |
| DCHECK(base); |
| if (!base) |
| return 0; |
| |
| WrapperStruct* wrapperStruct = |
| GetWrapperStruct(reinterpret_cast<StructName*>(base)); |
| // Verify that the wrapper offset was calculated correctly. |
| DCHECK_EQ(kWrapperType, wrapperStruct->type_); |
| |
| return wrapperStruct->wrapper_->Release(); |
| } |
| |
| static int CEF_CALLBACK struct_has_one_ref(cef_base_ref_counted_t* base) { |
| DCHECK(base); |
| if (!base) |
| return 0; |
| |
| WrapperStruct* wrapperStruct = |
| GetWrapperStruct(reinterpret_cast<StructName*>(base)); |
| // Verify that the wrapper offset was calculated correctly. |
| DCHECK_EQ(kWrapperType, wrapperStruct->type_); |
| |
| return wrapperStruct->wrapper_->HasOneRef(); |
| } |
| |
| static int CEF_CALLBACK |
| struct_has_at_least_one_ref(cef_base_ref_counted_t* base) { |
| DCHECK(base); |
| if (!base) |
| return 0; |
| |
| WrapperStruct* wrapperStruct = |
| GetWrapperStruct(reinterpret_cast<StructName*>(base)); |
| // Verify that the wrapper offset was calculated correctly. |
| DCHECK_EQ(kWrapperType, wrapperStruct->type_); |
| |
| return wrapperStruct->wrapper_->HasAtLeastOneRef(); |
| } |
| |
| WrapperStruct wrapper_struct_; |
| CefRefCount ref_count_; |
| |
| static CefWrapperType kWrapperType; |
| |
| DISALLOW_COPY_AND_ASSIGN(CefCppToCRefCounted); |
| }; |
| |
| #endif // CEF_LIBCEF_DLL_CPPTOC_CPPTOC_REF_COUNTED_H_ |