• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 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_SCOPED_H_
6 #define CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_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 CefCToCppScoped : public BaseName {
19  public:
20   CefCToCppScoped(const CefCToCppScoped&) = delete;
21   CefCToCppScoped& operator=(const CefCToCppScoped&) = delete;
22 
23   // Create a new wrapper instance for a structure reference received from the
24   // other side. The caller owns the CToCpp wrapper instance but not necessarily
25   // the underling object on the CppToC side (depends if s->del is non-NULL).
26   // The returned wrapper object can be used as either a scoped argument or to
27   // pass ownership. For example:
28   //
29   // void my_method(my_type1_t* struct1, my_type2_t* struct2) {
30   //  // Passes ownership to MyMethod1().
31   //  MyMethod1(MyType1CToCpp::Wrap(struct1));
32   //
33   //  // Passes reference to MyMethod2().
34   //  CefOwnPtr<MyType1> obj2 = MyType2CToCpp::Wrap(struct2);
35   //  MyMethod2(obj2.get());
36   //  // |obj2| is deleted when my_method() goes out of scope.
37   // }
38   //
39   // void MyMethod1(CefOwnPtr<MyType1> obj1) {
40   //   // |obj1| is deleted when MyMethod1() goes out of scope.
41   // }
42   //
43   // void MyMethod2(CefRawPtr<MyType2> obj2) {
44   // }
45   static CefOwnPtr<BaseName> Wrap(StructName* s);
46 
47   // Retrieve the underlying structure reference from a wrapper instance for
48   // return back to the other side. Ownership will be passed back to the other
49   // side and the wrapper will be deleted. For example:
50   //
51   // void MyMethod(CefOwnPtr<MyType> obj) {
52   //   // Ownership of the underlying MyType object is passed to my_method().
53   //   my_method(MyTypeCToCpp::UnwrapOwn(std::move(obj)));
54   //   // |obj| is now NULL.
55   // }
56   static StructName* UnwrapOwn(CefOwnPtr<BaseName> c);
57 
58   // Retrieve the underlying structure reference from a wrapper instance for
59   // return back to the other side. Ownership does not change. For example:
60   //
61   // void MyMethod(CefRawPtr<MyType> obj) {
62   //   // A reference is passed to my_method(). Ownership does not change.
63   //   my_method2(MyTypeCToCpp::UnwrapRaw(obj));
64   // }
65   static StructName* UnwrapRaw(CefRawPtr<BaseName> c);
66 
67   // Override delete operator to properly delete the WrapperStruct.
68   // ~CefCToCppScoped will be called first followed by this method.
69   static void operator delete(void* ptr);
70 
71  protected:
72   CefCToCppScoped() = default;
73   virtual ~CefCToCppScoped() = default;
74 
75   // If returning the structure across the DLL boundary use Unwrap() instead.
GetStruct()76   StructName* GetStruct() const {
77     WrapperStruct* wrapperStruct = GetWrapperStruct(this);
78     // Verify that the wrapper offset was calculated correctly.
79     DCHECK_EQ(kWrapperType, wrapperStruct->type_);
80     return wrapperStruct->struct_;
81   }
82 
83  private:
84   // Used to associate this wrapper object and the structure reference received
85   // from the other side.
86   struct WrapperStruct;
87 
88   static WrapperStruct* GetWrapperStruct(const BaseName* obj);
89 
90   // Unwrap as the derived type.
91   static StructName* UnwrapDerivedOwn(CefWrapperType type,
92                                       CefOwnPtr<BaseName> c);
93   static StructName* UnwrapDerivedRaw(CefWrapperType type,
94                                       CefRawPtr<BaseName> c);
95 
96   static CefWrapperType kWrapperType;
97 };
98 
99 template <class ClassName, class BaseName, class StructName>
100 struct CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct {
101   CefWrapperType type_;
102   StructName* struct_;
103   ClassName wrapper_;
104 };
105 
106 template <class ClassName, class BaseName, class StructName>
107 CefOwnPtr<BaseName> CefCToCppScoped<ClassName, BaseName, StructName>::Wrap(
108     StructName* s) {
109   if (!s)
110     return CefOwnPtr<BaseName>();
111 
112   // Wrap their structure with the CefCToCpp object.
113   WrapperStruct* wrapperStruct = new WrapperStruct;
114   wrapperStruct->type_ = kWrapperType;
115   wrapperStruct->struct_ = s;
116 
117   return CefOwnPtr<BaseName>(&wrapperStruct->wrapper_);
118 }
119 
120 template <class ClassName, class BaseName, class StructName>
121 StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapOwn(
122     CefOwnPtr<BaseName> c) {
123   if (!c.get())
124     return nullptr;
125 
126   WrapperStruct* wrapperStruct = GetWrapperStruct(c.get());
127 
128   // If the type does not match this object then we need to unwrap as the
129   // derived type.
130   if (wrapperStruct->type_ != kWrapperType)
131     return UnwrapDerivedOwn(wrapperStruct->type_, std::move(c));
132 
133   StructName* orig_struct = wrapperStruct->struct_;
134 
135 #if DCHECK_IS_ON()
136   // We should own the object currently.
137   cef_base_scoped_t* base = reinterpret_cast<cef_base_scoped_t*>(orig_struct);
138   DCHECK(base && base->del);
139 #endif
140 
141   // Don't delete the original object when the wrapper is deleted.
142   wrapperStruct->struct_ = nullptr;
143 
144   // Return the original structure.
145   return orig_struct;
146   // The wrapper |c| is deleted when this method goes out of scope.
147 }
148 
149 template <class ClassName, class BaseName, class StructName>
150 StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapRaw(
151     CefRawPtr<BaseName> c) {
152   if (!c)
153     return nullptr;
154 
155   WrapperStruct* wrapperStruct = GetWrapperStruct(c);
156 
157   // If the type does not match this object then we need to unwrap as the
158   // derived type.
159   if (wrapperStruct->type_ != kWrapperType)
160     return UnwrapDerivedRaw(wrapperStruct->type_, c);
161 
162   // Return the original structure.
163   return wrapperStruct->struct_;
164 }
165 
166 template <class ClassName, class BaseName, class StructName>
167 NO_SANITIZE("cfi-icall")
168 void CefCToCppScoped<ClassName, BaseName, StructName>::operator delete(
169     void* ptr) {
170   WrapperStruct* wrapperStruct = GetWrapperStruct(static_cast<BaseName*>(ptr));
171   // Verify that the wrapper offset was calculated correctly.
172   DCHECK_EQ(kWrapperType, wrapperStruct->type_);
173 
174   // May be NULL if UnwrapOwn() was called.
175   cef_base_scoped_t* base =
176       reinterpret_cast<cef_base_scoped_t*>(wrapperStruct->struct_);
177 
178   // If we own the object (base->del != NULL) then notify the other side that
179   // the object has been deleted.
180   if (base && base->del)
181     base->del(base);
182 
183   // Delete the wrapper structure without executing ~CefCToCppScoped() an
184   // additional time.
185   ::operator delete(wrapperStruct);
186 }
187 
188 template <class ClassName, class BaseName, class StructName>
189 typename CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct*
190 CefCToCppScoped<ClassName, BaseName, StructName>::GetWrapperStruct(
191     const BaseName* obj) {
192   // Offset using the WrapperStruct size instead of individual member sizes to
193   // avoid problems due to platform/compiler differences in structure padding.
194   return reinterpret_cast<WrapperStruct*>(
195       reinterpret_cast<char*>(const_cast<BaseName*>(obj)) -
196       (sizeof(WrapperStruct) - sizeof(ClassName)));
197 }
198 
199 #endif  // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_
200