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/capi/cef_base_capi.h" 11 #include "include/cef_base.h" 12 #include "libcef_dll/wrapper_types.h" 13 14 // Wrap a C structure with a C++ class. This is used when the implementation 15 // exists on the other side of the DLL boundary but will have methods called on 16 // this side of the DLL boundary. 17 template <class ClassName, class BaseName, class StructName> 18 class CefCToCppRefCounted : public BaseName { 19 public: 20 CefCToCppRefCounted(const CefCToCppRefCounted&) = delete; 21 CefCToCppRefCounted& operator=(const CefCToCppRefCounted&) = delete; 22 23 // Create a new wrapper instance for a structure reference received from the 24 // other side. 25 static CefRefPtr<BaseName> Wrap(StructName* s); 26 27 // Retrieve the underlying structure reference from a wrapper instance for 28 // return back to the other side. 29 static StructName* Unwrap(CefRefPtr<BaseName> c); 30 31 // CefBaseRefCounted methods increment/decrement reference counts on both this 32 // object and the underlying wrapped structure. AddRef()33 void AddRef() const { 34 UnderlyingAddRef(); 35 ref_count_.AddRef(); 36 } 37 bool Release() const; HasOneRef()38 bool HasOneRef() const { return UnderlyingHasOneRef(); } HasAtLeastOneRef()39 bool HasAtLeastOneRef() const { return UnderlyingHasAtLeastOneRef(); } 40 41 protected: 42 CefCToCppRefCounted() = default; 43 virtual ~CefCToCppRefCounted() = default; 44 45 // If returning the structure across the DLL boundary use Unwrap() instead. GetStruct()46 StructName* GetStruct() const { 47 WrapperStruct* wrapperStruct = GetWrapperStruct(this); 48 // Verify that the wrapper offset was calculated correctly. 49 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 50 return wrapperStruct->struct_; 51 } 52 53 private: 54 // Used to associate this wrapper object and the structure reference received 55 // from the other side. 56 struct WrapperStruct; 57 58 static WrapperStruct* GetWrapperStruct(const BaseName* obj); 59 60 // Unwrap as the derived type. 61 static StructName* UnwrapDerived(CefWrapperType type, BaseName* c); 62 63 // Increment/decrement reference counts on only the underlying class. 64 NO_SANITIZE("cfi-icall") UnderlyingAddRef()65 void UnderlyingAddRef() const { 66 cef_base_ref_counted_t* base = 67 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 68 if (base->add_ref) 69 base->add_ref(base); 70 } 71 72 NO_SANITIZE("cfi-icall") UnderlyingRelease()73 bool UnderlyingRelease() const { 74 cef_base_ref_counted_t* base = 75 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 76 if (!base->release) 77 return false; 78 return base->release(base) ? true : false; 79 } 80 81 NO_SANITIZE("cfi-icall") UnderlyingHasOneRef()82 bool UnderlyingHasOneRef() const { 83 cef_base_ref_counted_t* base = 84 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 85 if (!base->has_one_ref) 86 return false; 87 return base->has_one_ref(base) ? true : false; 88 } 89 90 NO_SANITIZE("cfi-icall") UnderlyingHasAtLeastOneRef()91 bool UnderlyingHasAtLeastOneRef() const { 92 cef_base_ref_counted_t* base = 93 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 94 if (!base->has_at_least_one_ref) 95 return false; 96 return base->has_at_least_one_ref(base) ? true : false; 97 } 98 99 CefRefCount ref_count_; 100 101 static CefWrapperType kWrapperType; 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