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_CPPTOC_CPPTOC_REF_COUNTED_H_ 6 #define CEF_LIBCEF_DLL_CPPTOC_CPPTOC_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++ class with a C structure. This is used when the class 15 // implementation exists on this side of the DLL boundary but will have methods 16 // called from the other side of the DLL boundary. 17 template <class ClassName, class BaseName, class StructName> 18 class CefCppToCRefCounted : public CefBaseRefCounted { 19 public: 20 CefCppToCRefCounted(const CefCppToCRefCounted&) = delete; 21 CefCppToCRefCounted& operator=(const CefCppToCRefCounted&) = delete; 22 23 // Create a new wrapper instance and associated structure reference for 24 // passing an object instance the other side. Wrap(CefRefPtr<BaseName> c)25 static StructName* Wrap(CefRefPtr<BaseName> c) { 26 if (!c.get()) 27 return nullptr; 28 29 // Wrap our object with the CefCppToCRefCounted class. 30 ClassName* wrapper = new ClassName(); 31 wrapper->wrapper_struct_.object_ = c.get(); 32 // Add a reference to our wrapper object that will be released once our 33 // structure arrives on the other side. 34 wrapper->AddRef(); 35 // Return the structure pointer that can now be passed to the other side. 36 return wrapper->GetStruct(); 37 } 38 39 // Retrieve the underlying object instance for a structure reference passed 40 // back from the other side. Unwrap(StructName * s)41 static CefRefPtr<BaseName> Unwrap(StructName* s) { 42 if (!s) 43 return nullptr; 44 45 // Cast our structure to the wrapper structure type. 46 WrapperStruct* wrapperStruct = GetWrapperStruct(s); 47 48 // If the type does not match this object then we need to unwrap as the 49 // derived type. 50 if (wrapperStruct->type_ != kWrapperType) 51 return UnwrapDerived(wrapperStruct->type_, s); 52 53 // Add the underlying object instance to a smart pointer. 54 CefRefPtr<BaseName> objectPtr(wrapperStruct->object_); 55 // Release the reference to our wrapper object that was added before the 56 // structure was passed back to us. 57 wrapperStruct->wrapper_->Release(); 58 // Return the underlying object instance. 59 return objectPtr; 60 } 61 62 // Retrieve the underlying object instance from our own structure reference 63 // when the reference is passed as the required first parameter of a C API 64 // function call. No explicit reference counting is done in this case. Get(StructName * s)65 static CefRefPtr<BaseName> Get(StructName* s) { 66 DCHECK(s); 67 WrapperStruct* wrapperStruct = GetWrapperStruct(s); 68 // Verify that the wrapper offset was calculated correctly. 69 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 70 return wrapperStruct->object_; 71 } 72 73 // If returning the structure across the DLL boundary you should call 74 // AddRef() on this CefCppToCRefCounted object. On the other side of the DLL 75 // boundary, call UnderlyingRelease() on the wrapping CefCToCpp object. GetStruct()76 StructName* GetStruct() { return &wrapper_struct_.struct_; } 77 78 // CefBaseRefCounted methods increment/decrement reference counts on both this 79 // object and the underlying wrapper class. AddRef()80 void AddRef() const { 81 UnderlyingAddRef(); 82 ref_count_.AddRef(); 83 } Release()84 bool Release() const { 85 UnderlyingRelease(); 86 if (ref_count_.Release()) { 87 delete this; 88 return true; 89 } 90 return false; 91 } HasOneRef()92 bool HasOneRef() const { return UnderlyingHasOneRef(); } HasAtLeastOneRef()93 bool HasAtLeastOneRef() const { return UnderlyingHasAtLeastOneRef(); } 94 95 protected: CefCppToCRefCounted()96 CefCppToCRefCounted() { 97 wrapper_struct_.type_ = kWrapperType; 98 wrapper_struct_.wrapper_ = this; 99 memset(GetStruct(), 0, sizeof(StructName)); 100 101 cef_base_ref_counted_t* base = 102 reinterpret_cast<cef_base_ref_counted_t*>(GetStruct()); 103 base->size = sizeof(StructName); 104 base->add_ref = struct_add_ref; 105 base->release = struct_release; 106 base->has_one_ref = struct_has_one_ref; 107 base->has_at_least_one_ref = struct_has_at_least_one_ref; 108 } 109 110 virtual ~CefCppToCRefCounted() = default; 111 112 private: 113 // Used to associate this wrapper object, the underlying object instance and 114 // the structure that will be passed to the other side. 115 struct WrapperStruct { 116 CefWrapperType type_; 117 BaseName* object_; 118 CefCppToCRefCounted<ClassName, BaseName, StructName>* wrapper_; 119 StructName struct_; 120 }; 121 GetWrapperStruct(StructName * s)122 static WrapperStruct* GetWrapperStruct(StructName* s) { 123 // Offset using the WrapperStruct size instead of individual member sizes 124 // to avoid problems due to platform/compiler differences in structure 125 // padding. 126 return reinterpret_cast<WrapperStruct*>( 127 reinterpret_cast<char*>(s) - 128 (sizeof(WrapperStruct) - sizeof(StructName))); 129 } 130 131 // Unwrap as the derived type. 132 static CefRefPtr<BaseName> UnwrapDerived(CefWrapperType type, StructName* s); 133 134 // Increment/decrement reference counts on only the underlying class. UnderlyingAddRef()135 void UnderlyingAddRef() const { wrapper_struct_.object_->AddRef(); } UnderlyingRelease()136 void UnderlyingRelease() const { wrapper_struct_.object_->Release(); } UnderlyingHasOneRef()137 bool UnderlyingHasOneRef() const { 138 return wrapper_struct_.object_->HasOneRef(); 139 } UnderlyingHasAtLeastOneRef()140 bool UnderlyingHasAtLeastOneRef() const { 141 return wrapper_struct_.object_->HasAtLeastOneRef(); 142 } 143 struct_add_ref(cef_base_ref_counted_t * base)144 static void CEF_CALLBACK struct_add_ref(cef_base_ref_counted_t* base) { 145 DCHECK(base); 146 if (!base) 147 return; 148 149 WrapperStruct* wrapperStruct = 150 GetWrapperStruct(reinterpret_cast<StructName*>(base)); 151 // Verify that the wrapper offset was calculated correctly. 152 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 153 154 wrapperStruct->wrapper_->AddRef(); 155 } 156 struct_release(cef_base_ref_counted_t * base)157 static int CEF_CALLBACK struct_release(cef_base_ref_counted_t* base) { 158 DCHECK(base); 159 if (!base) 160 return 0; 161 162 WrapperStruct* wrapperStruct = 163 GetWrapperStruct(reinterpret_cast<StructName*>(base)); 164 // Verify that the wrapper offset was calculated correctly. 165 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 166 167 return wrapperStruct->wrapper_->Release(); 168 } 169 struct_has_one_ref(cef_base_ref_counted_t * base)170 static int CEF_CALLBACK struct_has_one_ref(cef_base_ref_counted_t* base) { 171 DCHECK(base); 172 if (!base) 173 return 0; 174 175 WrapperStruct* wrapperStruct = 176 GetWrapperStruct(reinterpret_cast<StructName*>(base)); 177 // Verify that the wrapper offset was calculated correctly. 178 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 179 180 return wrapperStruct->wrapper_->HasOneRef(); 181 } 182 183 static int CEF_CALLBACK struct_has_at_least_one_ref(cef_base_ref_counted_t * base)184 struct_has_at_least_one_ref(cef_base_ref_counted_t* base) { 185 DCHECK(base); 186 if (!base) 187 return 0; 188 189 WrapperStruct* wrapperStruct = 190 GetWrapperStruct(reinterpret_cast<StructName*>(base)); 191 // Verify that the wrapper offset was calculated correctly. 192 DCHECK_EQ(kWrapperType, wrapperStruct->type_); 193 194 return wrapperStruct->wrapper_->HasAtLeastOneRef(); 195 } 196 197 WrapperStruct wrapper_struct_; 198 CefRefCount ref_count_; 199 200 static CefWrapperType kWrapperType; 201 }; 202 203 #endif // CEF_LIBCEF_DLL_CPPTOC_CPPTOC_REF_COUNTED_H_ 204