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