1 // Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #ifndef CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_ 6 #define CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_ 7 #pragma once 8 9 #include "include/base/cef_logging.h" 10 #include "include/base/cef_macros.h" 11 #include "include/capi/cef_base_capi.h" 12 #include "include/cef_base.h" 13 #include "libcef_dll/wrapper_types.h" 14 15 // Wrap a C structure with a C++ class. This is used when the implementation 16 // exists on the other side of the DLL boundary but will have methods called on 17 // this side of the DLL boundary. 18 template <class ClassName, class BaseName, class StructName> 19 class CefCToCppRefCounted : public BaseName { 20 public: 21 // Create a new wrapper instance for a structure reference received from the 22 // other side. 23 static CefRefPtr<BaseName> Wrap(StructName* s); 24 25 // Retrieve the underlying structure reference from a wrapper instance for 26 // return back to the other side. 27 static StructName* Unwrap(CefRefPtr<BaseName> c); 28 29 // CefBaseRefCounted methods increment/decrement reference counts on both this 30 // object and the underlying wrapped structure. AddRef()31 void AddRef() const { 32 UnderlyingAddRef(); 33 ref_count_.AddRef(); 34 } 35 bool Release() const; HasOneRef()36 bool HasOneRef() const { return UnderlyingHasOneRef(); } HasAtLeastOneRef()37 bool HasAtLeastOneRef() const { return UnderlyingHasAtLeastOneRef(); } 38 39 protected: CefCToCppRefCounted()40 CefCToCppRefCounted() {} ~CefCToCppRefCounted()41 virtual ~CefCToCppRefCounted() {} 42 43 // If returning the structure across the DLL boundary use Unwrap() instead. GetStruct()44 StructName* GetStruct() const { 45 WrapperStruct* wrapperStruct = GetWrapperStruct(this); 46 // Verify that the wrapper offset was calculated correctly. 47 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 48 return wrapperStruct->struct_; 49 } 50 51 private: 52 // Used to associate this wrapper object and the structure reference received 53 // from the other side. 54 struct WrapperStruct; 55 56 static WrapperStruct* GetWrapperStruct(const BaseName* obj); 57 58 // Unwrap as the derived type. 59 static StructName* UnwrapDerived(CefWrapperType type, BaseName* c); 60 61 // Increment/decrement reference counts on only the underlying class. 62 NO_SANITIZE("cfi-icall") UnderlyingAddRef()63 void UnderlyingAddRef() const { 64 cef_base_ref_counted_t* base = 65 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 66 if (base->add_ref) 67 base->add_ref(base); 68 } 69 70 NO_SANITIZE("cfi-icall") UnderlyingRelease()71 bool UnderlyingRelease() const { 72 cef_base_ref_counted_t* base = 73 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 74 if (!base->release) 75 return false; 76 return base->release(base) ? true : false; 77 } 78 79 NO_SANITIZE("cfi-icall") UnderlyingHasOneRef()80 bool UnderlyingHasOneRef() const { 81 cef_base_ref_counted_t* base = 82 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 83 if (!base->has_one_ref) 84 return false; 85 return base->has_one_ref(base) ? true : false; 86 } 87 88 NO_SANITIZE("cfi-icall") UnderlyingHasAtLeastOneRef()89 bool UnderlyingHasAtLeastOneRef() const { 90 cef_base_ref_counted_t* base = 91 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 92 if (!base->has_one_ref) 93 return false; 94 return base->has_at_least_one_ref(base) ? true : false; 95 } 96 97 CefRefCount ref_count_; 98 99 static CefWrapperType kWrapperType; 100 101 DISALLOW_COPY_AND_ASSIGN(CefCToCppRefCounted); 102 }; 103 104 template <class ClassName, class BaseName, class StructName> 105 struct CefCToCppRefCounted<ClassName, BaseName, StructName>::WrapperStruct { 106 CefWrapperType type_; 107 StructName* struct_; 108 ClassName wrapper_; 109 }; 110 111 template <class ClassName, class BaseName, class StructName> 112 CefRefPtr<BaseName> CefCToCppRefCounted<ClassName, BaseName, StructName>::Wrap( 113 StructName* s) { 114 if (!s) 115 return nullptr; 116 117 // Wrap their structure with the CefCToCppRefCounted object. 118 WrapperStruct* wrapperStruct = new WrapperStruct; 119 wrapperStruct->type_ = kWrapperType; 120 wrapperStruct->struct_ = s; 121 122 // Put the wrapper object in a smart pointer. 123 CefRefPtr<BaseName> wrapperPtr(&wrapperStruct->wrapper_); 124 // Release the reference that was added to the CefCppToC wrapper object on 125 // the other side before their structure was passed to us. 126 wrapperStruct->wrapper_.UnderlyingRelease(); 127 // Return the smart pointer. 128 return wrapperPtr; 129 } 130 131 template <class ClassName, class BaseName, class StructName> 132 StructName* CefCToCppRefCounted<ClassName, BaseName, StructName>::Unwrap( 133 CefRefPtr<BaseName> c) { 134 if (!c.get()) 135 return nullptr; 136 137 WrapperStruct* wrapperStruct = GetWrapperStruct(c.get()); 138 139 // If the type does not match this object then we need to unwrap as the 140 // derived type. 141 if (wrapperStruct->type_ != kWrapperType) 142 return UnwrapDerived(wrapperStruct->type_, c.get()); 143 144 // Add a reference to the CefCppToC wrapper object on the other side that 145 // will be released once the structure is received. 146 wrapperStruct->wrapper_.UnderlyingAddRef(); 147 // Return their original structure. 148 return wrapperStruct->struct_; 149 } 150 151 template <class ClassName, class BaseName, class StructName> 152 bool CefCToCppRefCounted<ClassName, BaseName, StructName>::Release() const { 153 UnderlyingRelease(); 154 if (ref_count_.Release()) { 155 WrapperStruct* wrapperStruct = GetWrapperStruct(this); 156 // Verify that the wrapper offset was calculated correctly. 157 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 158 delete wrapperStruct; 159 return true; 160 } 161 return false; 162 } 163 164 template <class ClassName, class BaseName, class StructName> 165 typename CefCToCppRefCounted<ClassName, BaseName, StructName>::WrapperStruct* 166 CefCToCppRefCounted<ClassName, BaseName, StructName>::GetWrapperStruct( 167 const BaseName* obj) { 168 // Offset using the WrapperStruct size instead of individual member sizes to 169 // avoid problems due to platform/compiler differences in structure padding. 170 return reinterpret_cast<WrapperStruct*>( 171 reinterpret_cast<char*>(const_cast<BaseName*>(obj)) - 172 (sizeof(WrapperStruct) - sizeof(ClassName))); 173 } 174 175 #endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_ 176