• 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_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