Bug 795804 - Use WeakPtr for nsTextEditorState where appropriate; r=ehsan a=akeybl
authorAryeh Gregor <ayg@aryeh.name>
Sun, 14 Oct 2012 10:10:16 +0200
changeset 82031 a0ae1918be120a0903ac9a95a9a7fce648c532a5
parent 82030 d61843854f3370de0e34a0173e8db9064390a6f1
child 82032 53363548ad9bd6bea6096a674116c3f710308db8
push id299
push usereakhgari@mozilla.com
push dateThu, 18 Oct 2012 23:56:09 +0000
reviewersehsan, akeybl
bugs795804
milestone10.0.10esrpre
Bug 795804 - Use WeakPtr for nsTextEditorState where appropriate; r=ehsan a=akeybl
content/html/content/src/nsTextEditorState.cpp
content/html/content/src/nsTextEditorState.h
js/src/Makefile.in
mfbt/NullPtr.h
mfbt/TypeTraits.h
mfbt/WeakPtr.h
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -63,16 +63,17 @@
 #include "nsISelectionPrivate.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIEditor.h"
 #include "nsTextEditRules.h"
 #include "nsEventListenerManager.h"
 #include "nsContentUtils.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
 
 static nsINativeKeyBindings *sNativeInputBindings = nsnull;
 static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
 
 class RestoreSelectionState : public nsRunnable {
@@ -1006,39 +1007,41 @@ nsTextEditorState::GetSelectionControlle
 }
 
 // Helper class, used below in BindToFrame().
 class PrepareEditorEvent : public nsRunnable {
 public:
   PrepareEditorEvent(nsTextEditorState &aState,
                      nsIContent *aOwnerContent,
                      const nsAString &aCurrentValue)
-    : mState(aState)
+    : mState(aState.asWeakPtr())
     , mOwnerContent(aOwnerContent)
     , mCurrentValue(aCurrentValue)
   {
-    mState.mValueTransferInProgress = true;
+    aState.mValueTransferInProgress = true;
   }
 
   NS_IMETHOD Run() {
+    NS_ENSURE_TRUE(mState, NS_ERROR_NULL_POINTER);
+
     // Transfer the saved value to the editor if we have one
     const nsAString *value = nsnull;
     if (!mCurrentValue.IsEmpty()) {
       value = &mCurrentValue;
     }
 
-    mState.PrepareEditor(value);
+    mState->PrepareEditor(value);
 
-    mState.mValueTransferInProgress = false;
+    mState->mValueTransferInProgress = false;
 
     return NS_OK;
   }
 
 private:
-  nsTextEditorState &mState;
+  WeakPtr<nsTextEditorState> mState;
   nsCOMPtr<nsIContent> mOwnerContent; // strong reference
   nsAutoString mCurrentValue;
 };
 
 nsresult
 nsTextEditorState::BindToFrame(nsTextControlFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "The frame to bind to should be valid");
--- a/content/html/content/src/nsTextEditorState.h
+++ b/content/html/content/src/nsTextEditorState.h
@@ -39,16 +39,17 @@
 #ifndef nsTextEditorState_h__
 #define nsTextEditorState_h__
 
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "nsITextControlElement.h"
 #include "nsITextControlFrame.h"
 #include "nsCycleCollectionParticipant.h"
+#include "mozilla/WeakPtr.h"
 
 class nsTextInputListener;
 class nsTextControlFrame;
 class nsTextInputSelectionImpl;
 class nsAnonDivObserver;
 class nsISelectionController;
 class nsFrameSelection;
 class nsIEditor;
@@ -143,17 +144,17 @@ class nsITextControlElement;
  *
  *   * If the text editor state object is unbound from the control's frame, the value is
  *     transferred to the mValue member variable, and will be managed there until a new
  *     frame is bound to the text editor state object.
  */
 
 class RestoreSelectionState;
 
-class nsTextEditorState {
+class nsTextEditorState : public mozilla::SupportsWeakPtr<nsTextEditorState> {
 public:
   explicit nsTextEditorState(nsITextControlElement* aOwningElement);
   ~nsTextEditorState();
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTextEditorState)
   NS_INLINE_DECL_REFCOUNTING(nsTextEditorState)
 
   nsIEditor* GetEditor();
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -277,20 +277,23 @@ EXPORTS_js = \
 #
 VPATH		+= \
 		$(srcdir)/../../mfbt \
 		$(NULL)
 
 EXPORTS_NAMESPACES += mozilla
 
 EXPORTS_mozilla = \
+		NullPtr.h \
 		RangedPtr.h \
 		RefPtr.h \
 		Types.h	\
+		TypeTraits.h	\
 		Util.h \
+		WeakPtr.h \
 		$(NULL)
 
 ifdef ENABLE_TRACEJIT
 VPATH		+= \
 		$(srcdir)/tracejit \
 		$(srcdir)/nanojit \
 
 INSTALLED_HEADERS += \
new file mode 100644
--- /dev/null
+++ b/mfbt/NullPtr.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Implements a workaround for compilers which do not support the C++11 nullptr
+ * constant.
+ */
+
+#ifndef mozilla_NullPtr_h_
+#define mozilla_NullPtr_h_
+
+#if defined(__clang__)
+#  ifndef __has_extension
+#    define __has_extension __has_feature
+#  endif
+#  if __has_extension(cxx_nullptr)
+#    define MOZ_HAVE_CXX11_NULLPTR
+#  endif
+#elif defined(__GNUC__)
+#  if defined(_GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+#    if (__GNUC__ * 1000 + __GNU_MINOR__) >= 4006
+#      define MOZ_HAVE_CXX11_NULLPTR
+#    endif
+#  endif
+#elif _MSC_VER >= 1600
+# define MOZ_HAVE_CXX11_NULLPTR
+#endif
+
+/**
+ * Use C++11 nullptr if available; otherwise use __null for gcc, or a 0 literal
+ * with the correct size to match the size of a pointer on a given platform.
+ */
+
+#ifndef MOZ_HAVE_CXX11_NULLPTR
+#  if defined(__GNUC__)
+#    define nullptr __null
+#  elif defined(_WIN64)
+#    define nullptr 0LL
+#  else
+#    define nullptr 0L
+#  endif
+#endif
+
+#endif  /* mozilla_NullPtr_h_ */
new file mode 100644
--- /dev/null
+++ b/mfbt/TypeTraits.h
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Template-based metaprogramming and type-testing facilities. */
+
+#ifndef mozilla_TypeTraits_h_
+#define mozilla_TypeTraits_h_
+
+namespace mozilla {
+
+/*
+ * IsBaseOf allows to know whether a given class is derived from another.
+ *
+ * Consider the following class definitions:
+ *
+ *   class A {};
+ *   class B : public A {};
+ *   class C {};
+ *
+ * mozilla::IsBaseOf<A, B>::value is true;
+ * mozilla::IsBaseOf<A, C>::value is false;
+ */
+template<class Base, class Derived>
+class IsBaseOf
+{
+  private:
+    static char test(Base* b);
+    static int test(...);
+
+  public:
+    static const bool value =
+      sizeof(test(static_cast<Derived*>(0))) == sizeof(char);
+};
+
+/*
+ * IsConvertible determines whether a value of type From will implicitly convert
+ * to a value of type To.  For example:
+ *
+ *   struct A {};
+ *   struct B : public A {};
+ *   struct C {};
+ *
+ * mozilla::IsConvertible<A, A>::value is true;
+ * mozilla::IsConvertible<A*, A*>::value is true;
+ * mozilla::IsConvertible<B, A>::value is true;
+ * mozilla::IsConvertible<B*, A*>::value is true;
+ * mozilla::IsConvertible<C, A>::value is false;
+ * mozilla::IsConvertible<A, C>::value is false;
+ * mozilla::IsConvertible<A*, C*>::value is false;
+ * mozilla::IsConvertible<C*, A*>::value is false.
+ *
+ * For obscure reasons, you can't use IsConvertible when the types being tested
+ * are related through private inheritance, and you'll get a compile error if
+ * you try.  Just don't do it!
+ */
+template<typename From, typename To>
+struct IsConvertible
+{
+  private:
+    static From create();
+
+    template<typename From1, typename To1>
+    static char test(To to);
+
+    template<typename From1, typename To1>
+    static int test(...);
+
+  public:
+    static const bool value =
+      sizeof(test<From, To>(create())) == sizeof(char);
+};
+
+/*
+ * Conditional selects a class between two, depending on a given boolean value.
+ *
+ * mozilla::Conditional<true, A, B>::Type is A;
+ * mozilla::Conditional<false, A, B>::Type is B;
+ */
+template<bool condition, class A, class B>
+struct Conditional
+{
+    typedef A Type;
+};
+
+template<class A, class B>
+struct Conditional<false, A, B>
+{
+    typedef B Type;
+};
+
+/*
+ * EnableIf is a struct containing a typedef of T if and only if B is true.
+ *
+ * mozilla::EnableIf<true, int>::Type is int;
+ * mozilla::EnableIf<false, int>::Type is a compile-time error.
+ *
+ * Use this template to implement SFINAE-style (Substitution Failure Is not An
+ * Error) requirements.  For example, you might use it to impose a restriction
+ * on a template parameter:
+ *
+ *   template<typename T>
+ *   class PodVector // vector optimized to store POD (memcpy-able) types
+ *   {
+ *      EnableIf<IsPodType<T>, T>::Type* vector;
+ *      size_t length;
+ *      ...
+ *   };
+ */
+template<bool B, typename T = void>
+struct EnableIf
+{};
+
+template<typename T>
+struct EnableIf<true, T>
+{
+    typedef T Type;
+};
+
+} /* namespace mozilla */
+
+#endif  /* mozilla_TypeTraits_h_ */
new file mode 100644
--- /dev/null
+++ b/mfbt/WeakPtr.h
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Weak pointer functionality, implemented as a mixin for use with any class. */
+
+/**
+ * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
+ * its lifetime. It works by creating a single shared reference counted object
+ * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
+ * clear the pointer in the WeakReference without having to know about all of
+ * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
+ * of 'Foo'.
+ *
+ * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
+ * dereference, and an additional heap allocated pointer sized object shared
+ * between all of the WeakPtrs.
+ *
+ * Example of usage:
+ *
+ *   // To have a class C support weak pointers, inherit from SupportsWeakPtr<C>.
+ *   class C : public SupportsWeakPtr<C>
+ *   {
+ *    public:
+ *      int num;
+ *      void act();
+ *   };
+ *
+ *   C* ptr =  new C();
+ *
+ *   // Get weak pointers to ptr. The first time asWeakPtr is called
+ *   // a reference counted WeakReference object is created that
+ *   // can live beyond the lifetime of 'ptr'. The WeakReference
+ *   // object will be notified of 'ptr's destruction.
+ *   WeakPtr<C> weak = ptr->asWeakPtr();
+ *   WeakPtr<C> other = ptr->asWeakPtr();
+ *
+ *   // Test a weak pointer for validity before using it.
+ *   if (weak) {
+ *     weak->num = 17;
+ *     weak->act();
+ *   }
+ *
+ *   // Destroying the underlying object clears weak pointers to it.
+ *   delete ptr;
+ *
+ *   MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
+ *   MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
+ *
+ * WeakPtr is typesafe and may be used with any class. It is not required that
+ * the class be reference-counted or allocated in any particular way.
+ *
+ * The API was loosely inspired by Chromium's weak_ptr.h:
+ * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
+ */
+
+#ifndef mozilla_WeakPtr_h_
+#define mozilla_WeakPtr_h_
+
+#include "mozilla/NullPtr.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/TypeTraits.h"
+
+namespace mozilla {
+
+template <typename T> class WeakPtr;
+
+template <typename T>
+class SupportsWeakPtr
+{
+  public:
+    WeakPtr<T> asWeakPtr() {
+      if (!weakRef)
+        weakRef = new WeakReference(static_cast<T*>(this));
+      return WeakPtr<T>(weakRef);
+    }
+
+  protected:
+    ~SupportsWeakPtr() {
+      if (weakRef)
+        weakRef->detach();
+    }
+
+  private:
+    friend class WeakPtr<T>;
+
+    // This can live beyond the lifetime of the class derived from SupportsWeakPtr.
+    class WeakReference : public RefCounted<WeakReference>
+    {
+      public:
+        explicit WeakReference(T* ptr) : ptr(ptr) {}
+        T* get() const {
+          return ptr;
+        }
+
+      private:
+        friend class WeakPtr<T>;
+        friend class SupportsWeakPtr<T>;
+        void detach() {
+          ptr = nullptr;
+        }
+        T* ptr;
+    };
+
+    RefPtr<WeakReference> weakRef;
+};
+
+template <typename T>
+class WeakPtr
+{
+  public:
+    WeakPtr(const WeakPtr<T>& o) : ref(o.ref) {}
+    WeakPtr() : ref(nullptr) {}
+
+    operator T*() const {
+      return ref->get();
+    }
+    T& operator*() const {
+      return *ref->get();
+    }
+
+    T* operator->() const {
+      return ref->get();
+    }
+
+  private:
+    friend class SupportsWeakPtr<T>;
+
+    explicit WeakPtr(const RefPtr<typename SupportsWeakPtr<T>::WeakReference> &o) : ref(o) {}
+
+    RefPtr<typename SupportsWeakPtr<T>::WeakReference> ref;
+};
+
+} // namespace mozilla
+
+#endif /* ifdef mozilla_WeakPtr_h_ */