• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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