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