OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef CHROME_FRAME_SCOPED_NS_PTR_WIN_H_ |
| 6 #define CHROME_FRAME_SCOPED_NS_PTR_WIN_H_ |
| 7 |
| 8 #include "base/logging.h" |
| 9 #include "base/ref_counted.h" |
| 10 |
| 11 #include "third_party/xulrunner-sdk/win/include/xpcom/nsISupports.h" |
| 12 |
| 13 |
| 14 // Utility template to prevent users of ScopedNsPtr from calling AddRef and/or |
| 15 // Release() without going through the ScopedNsPtr class. |
| 16 template <class nsInterface> |
| 17 class BlocknsISupportsMethods : public nsInterface { |
| 18 private: |
| 19 NS_IMETHOD QueryInterface(REFNSIID iid, void** object) = 0; |
| 20 NS_IMETHOD_(nsrefcnt) AddRef() = 0; |
| 21 NS_IMETHOD_(nsrefcnt) Release() = 0; |
| 22 }; |
| 23 |
| 24 // A smart pointer class for nsISupports. |
| 25 // Based on ScopedComPtr. |
| 26 // We have our own class instead of nsCOMPtr. nsCOMPtr has parts of its |
| 27 // implementation in the xpcomglue lib which we can't use since that lib |
| 28 // is built with incompatible build flags to ours. |
| 29 template <class nsInterface, |
| 30 const nsIID* interface_id = |
| 31 reinterpret_cast<const nsIID*>(&__uuidof(nsInterface))> |
| 32 class ScopedNsPtr : public scoped_refptr<nsInterface> { |
| 33 public: |
| 34 typedef scoped_refptr<nsInterface> ParentClass; |
| 35 |
| 36 ScopedNsPtr() { |
| 37 } |
| 38 |
| 39 explicit ScopedNsPtr(nsInterface* p) : ParentClass(p) { |
| 40 } |
| 41 |
| 42 explicit ScopedNsPtr(const ScopedNsPtr<nsInterface, interface_id>& p) |
| 43 : ParentClass(p) { |
| 44 } |
| 45 |
| 46 ~ScopedNsPtr() { |
| 47 // We don't want the smart pointer class to be bigger than the pointer |
| 48 // it wraps. |
| 49 COMPILE_ASSERT(sizeof(ScopedNsPtr<nsInterface, interface_id>) == |
| 50 sizeof(nsInterface*), ScopedNsPtrSize); |
| 51 } |
| 52 |
| 53 // Explicit Release() of the held object. Useful for reuse of the |
| 54 // ScopedNsPtr instance. |
| 55 // Note that this function equates to nsISupports::Release and should not |
| 56 // be confused with e.g. scoped_ptr::release(). |
| 57 void Release() { |
| 58 if (ptr_ != NULL) { |
| 59 ptr_->Release(); |
| 60 ptr_ = NULL; |
| 61 } |
| 62 } |
| 63 |
| 64 // Sets the internal pointer to NULL and returns the held object without |
| 65 // releasing the reference. |
| 66 nsInterface* Detach() { |
| 67 nsInterface* p = ptr_; |
| 68 ptr_ = NULL; |
| 69 return p; |
| 70 } |
| 71 |
| 72 // Accepts an interface pointer that has already been addref-ed. |
| 73 void Attach(nsInterface* p) { |
| 74 DCHECK(ptr_ == NULL); |
| 75 ptr_ = p; |
| 76 } |
| 77 |
| 78 // Retrieves the pointer address. |
| 79 // Used to receive object pointers as out arguments (and take ownership). |
| 80 // The function DCHECKs on the current value being NULL. |
| 81 // Usage: Foo(p.Receive()); |
| 82 nsInterface** Receive() { |
| 83 DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL"; |
| 84 return &ptr_; |
| 85 } |
| 86 |
| 87 template <class Query> |
| 88 nsresult QueryInterface(Query** p) { |
| 89 DCHECK(p != NULL); |
| 90 DCHECK(ptr_ != NULL); |
| 91 return ptr_->QueryInterface(Query::GetIID(), reinterpret_cast<void**>(p)); |
| 92 } |
| 93 |
| 94 template <class Query> |
| 95 nsresult QueryInterface(const nsIID& iid, Query** p) { |
| 96 DCHECK(p != NULL); |
| 97 DCHECK(ptr_ != NULL); |
| 98 return ptr_->QueryInterface(iid, reinterpret_cast<void**>(p)); |
| 99 } |
| 100 |
| 101 // Queries |other| for the interface this object wraps and returns the |
| 102 // error code from the other->QueryInterface operation. |
| 103 nsresult QueryFrom(nsISupports* other) { |
| 104 DCHECK(other != NULL); |
| 105 return other->QueryInterface(iid(), reinterpret_cast<void**>(Receive())); |
| 106 } |
| 107 |
| 108 // Checks if the identity of |other| and this object is the same. |
| 109 bool IsSameObject(nsISupports* other) { |
| 110 if (!other && !ptr_) |
| 111 return true; |
| 112 |
| 113 if (!other || !ptr_) |
| 114 return false; |
| 115 |
| 116 nsIID iid = NS_ISUPPORTS_IID; |
| 117 ScopedNsPtr<nsISupports, iid> my_identity; |
| 118 QueryInterface(my_identity.Receive()); |
| 119 |
| 120 ScopedNsPtr<nsISupports, iid> other_identity; |
| 121 other->QueryInterface(other_identity.Receive()); |
| 122 |
| 123 return static_cast<nsISupports*>(my_identity) == |
| 124 static_cast<nsISupports*>(other_identity); |
| 125 } |
| 126 |
| 127 // Provides direct access to the interface. |
| 128 // Here we use a well known trick to make sure we block access to |
| 129 // IUknown methods so that something bad like this doesn't happen: |
| 130 // ScopedNsPtr<nsISupports> p(Foo()); |
| 131 // p->Release(); |
| 132 // ... later the destructor runs, which will Release() again. |
| 133 // and to get the benefit of the DCHECKs we add to QueryInterface. |
| 134 // There's still a way to call these methods if you absolutely must |
| 135 // by statically casting the ScopedNsPtr instance to the wrapped interface |
| 136 // and then making the call... but generally that shouldn't be necessary. |
| 137 BlocknsISupportsMethods<nsInterface>* operator->() const { |
| 138 DCHECK(ptr_ != NULL); |
| 139 return reinterpret_cast<BlocknsISupportsMethods<nsInterface>*>(ptr_); |
| 140 } |
| 141 |
| 142 // static methods |
| 143 |
| 144 static const nsIID& iid() { |
| 145 return *interface_id; |
| 146 } |
| 147 }; |
| 148 |
| 149 #endif // CHROME_FRAME_SCOPED_NS_PTR_WIN_H_ |
OLD | NEW |