Bug 373344, r+sr=roc, a=blocking1.9+
authorOlli.Pettay@helsinki.fi
Thu, 22 Nov 2007 07:08:13 -0800
changeset 8292 12e9fb6a88f8f8b0f1474e01beed58259d1545ba
parent 8291 6d98c525481996a190b0e7b9def70bddca2e0df7
child 8293 a113fd0a3fc1e9b6112a1e0f848d147e64cb1110
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblocking1.9
bugs373344
milestone1.9b2pre
Bug 373344, r+sr=roc, a=blocking1.9+
layout/base/nsPresShell.cpp
view/public/nsIView.h
view/src/nsView.cpp
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5771,16 +5771,17 @@ PresShell::HandleEventInternal(nsEvent* 
     nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput);
 
     nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
 
     // FIXME. If the event was reused, we need to clear the old target,
     // bug 329430
     aEvent->target = nsnull;
 
+    nsWeakView weakView(aView);
     // 1. Give event to event manager for pre event state changes and
     //    generation of synthetic events.
     rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
                                  aStatus, aView);
 
     // 2. Give event to the DOM for third party and JS use.
     if ((GetCurrentEventFrame()) && NS_SUCCEEDED(rv)) {
       // We want synthesized mouse moves to cause mouseover and mouseout
@@ -5804,17 +5805,18 @@ PresShell::HandleEventInternal(nsEvent* 
           }
         }
       }
 
       // 3. Give event to event manager for post event state changes and
       //    generation of synthetic events.
       if (NS_SUCCEEDED(rv)) {
         rv = manager->PostHandleEvent(mPresContext, aEvent,
-                                      GetCurrentEventFrame(), aStatus, aView);
+                                      GetCurrentEventFrame(), aStatus,
+                                      weakView.GetView());
       }
     }
   }
   return rv;
 }
 
 // Dispatch event to content only (NOT full processing)
 // See also HandleEventWithTarget which does full event processing.
--- a/view/public/nsIView.h
+++ b/view/public/nsIView.h
@@ -42,31 +42,32 @@
 #include "nsRect.h"
 #include "nsPoint.h"
 #include "nsIWidget.h"
 
 class nsIViewManager;
 class nsIScrollableView;
 class nsViewManager;
 class nsView;
+class nsWeakView;
 
 // Enumerated type to indicate the visibility of a layer.
 // hide - the layer is not shown.
 // show - the layer is shown irrespective of the visibility of 
 //        the layer's parent.
 enum nsViewVisibility {
   nsViewVisibility_kHide = 0,
   nsViewVisibility_kShow = 1
 };
 
 // IID for the nsIView interface
-// 6610ae89-3909-422f-a227-ede67b97bcd1
+// 1b0215f7-f5d1-4574-9ab9-abdcceddb82e
 #define NS_IVIEW_IID    \
-{ 0x6610ae89, 0x3909, 0x422f, \
-{ 0xa2, 0x27, 0xed, 0xe6, 0x7b, 0x97, 0xbc, 0xd1 } }
+{ 0x1b0215f7, 0xf5d1, 0x4574, \
+  { 0x9a, 0xb9, 0xab, 0xdc, 0xce, 0xdd, 0xb8, 0x2e } }
 
 // Public view flags are defined in this file
 #define NS_VIEW_FLAGS_PUBLIC              0x00FF
 // Private view flags are private to the view module,
 // and are defined in nsView.h
 #define NS_VIEW_FLAGS_PRIVATE             0xFF00
 
 // Public view flags
@@ -77,16 +78,20 @@ enum nsViewVisibility {
 // Indicates that the view is a floating view.
 #define NS_VIEW_FLAG_FLOATING             0x0008
 
 // If set it indicates that this view should be
 // displayed above z-index:auto views if this view 
 // is z-index:auto also
 #define NS_VIEW_FLAG_TOPMOST              0x0010
 
+// If set, the view disowns the widget and leaves it up
+// to other code to destroy it.
+#define NS_VIEW_DISOWNS_WIDGET             0x0020
+
 struct nsViewZIndex {
   PRBool mIsAuto;
   PRInt32 mZIndex;
   PRBool mIsTopmost;
   
   nsViewZIndex(PRBool aIsAuto, PRInt32 aZIndex, PRBool aIsTopmost)
     : mIsAuto(aIsAuto), mZIndex(aZIndex), mIsTopmost(aIsTopmost) {}
 };
@@ -299,17 +304,17 @@ public:
    */
   PRBool HasWidget() const { return mWindow != nsnull; }
 
   /**
    * If called, will make the view disown the widget and leave it up
    * to other code to destroy it.
    */
   void DisownWidget() {
-    mWidgetDisowned = PR_TRUE;
+    mVFlags |= NS_VIEW_DISOWNS_WIDGET;
   }
 
 #ifdef DEBUG
   /**
    * Output debug info to FILE
    * @param out output file handle
    * @param aIndent indentation depth
    * NOTE: virtual so that debugging tools not linked into gklayout can access it
@@ -319,29 +324,74 @@ public:
 
   /**
    * @result true iff this is the root view for its view manager
    */
   PRBool IsRoot() const;
 
   virtual PRBool ExternalIsRoot() const;
 
+  void SetDeletionObserver(nsWeakView* aDeletionObserver);
 protected:
+  friend class nsWeakView;
   nsViewManager     *mViewManager;
   nsView            *mParent;
   nsIWidget         *mWindow;
   nsView            *mNextSibling;
   nsView            *mFirstChild;
   void              *mClientData;
   PRInt32           mZIndex;
   nsViewVisibility  mVis;
   nscoord           mPosX, mPosY;
   nsRect            mDimBounds; // relative to parent
   float             mOpacity;
   PRUint32          mVFlags;
-  PRBool            mWidgetDisowned;
+  nsWeakView*       mDeletionObserver;
 
   virtual ~nsIView() {}
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIView, NS_IVIEW_IID)
 
+// nsWeakViews must *not* be used in heap!
+class nsWeakView
+{
+public:
+  nsWeakView(nsIView* aView) : mPrev(nsnull), mView(aView)
+  {
+    if (mView) {
+      mView->SetDeletionObserver(this);
+    }
+  }
+
+  ~nsWeakView()
+  {
+    if (mView) {
+      NS_ASSERTION(mView->mDeletionObserver == this,
+                   "nsWeakViews deleted in wrong order!");
+      // Clear deletion observer temporarily.
+      mView->SetDeletionObserver(nsnull);
+      // Put back the previous deletion observer.
+      mView->SetDeletionObserver(mPrev);
+    }
+  }
+
+  PRBool IsAlive() { return !!mView; }
+
+  nsIView* GetView() { return mView; }
+
+  void SetPrevious(nsWeakView* aWeakView) { mPrev = aWeakView; }
+
+  void Clear()
+  {
+    if (mPrev) {
+      mPrev->Clear();
+    }
+    mView = nsnull;
+  }
+private:
+  static void* operator new(size_t) CPP_THROW_NEW { return 0; }
+  static void operator delete(void*, size_t) {}
+  nsWeakView* mPrev;
+  nsIView*    mView;
+};
+
 #endif
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -178,17 +178,17 @@ nsView::nsView(nsViewManager* aViewManag
   mVis = aVisibility;
   // Views should be transparent by default. Not being transparent is
   // a promise that the view will paint all its pixels opaquely. Views
   // should make this promise explicitly by calling
   // SetViewContentTransparency.
   mVFlags = 0;
   mViewManager = aViewManager;
   mDirtyRegion = nsnull;
-  mWidgetDisowned = PR_FALSE;
+  mDeletionObserver = nsnull;
 }
 
 void nsView::DropMouseGrabbing() {
   // check to see if we are grabbing events
   if (mViewManager->GetMouseEventGrabber() == this) {
     // we are grabbing events. Move the grab to the parent if we can.
     PRBool boolResult; //not used
     // if GetParent() returns null, then we release the grab, which is the best we can do
@@ -246,22 +246,26 @@ nsView::~nsView()
   // Destroy and release the widget
   if (mWindow)
   {
     // Release memory for the view wrapper
     ViewWrapper* wrapper = GetWrapperFor(mWindow);
     NS_IF_RELEASE(wrapper);
 
     mWindow->SetClientData(nsnull);
-    if (!mWidgetDisowned) {
+    if (!(mVFlags & NS_VIEW_DISOWNS_WIDGET)) {
       mWindow->Destroy();
     }
     NS_RELEASE(mWindow);
   }
   delete mDirtyRegion;
+
+  if (mDeletionObserver) {
+    mDeletionObserver->Clear();
+  }
 }
 
 nsresult nsView::QueryInterface(const nsIID& aIID, void** aInstancePtr)
 {
   if (nsnull == aInstancePtr) {
     return NS_ERROR_NULL_POINTER;
   }
 
@@ -831,8 +835,17 @@ PRBool nsIView::IsRoot() const
   NS_ASSERTION(mViewManager != nsnull," View manager is null in nsView::IsRoot()");
   return mViewManager->GetRootView() == this;
 }
 
 PRBool nsIView::ExternalIsRoot() const
 {
   return nsIView::IsRoot();
 }
+
+void
+nsIView::SetDeletionObserver(nsWeakView* aDeletionObserver)
+{
+  if (mDeletionObserver && aDeletionObserver) {
+    aDeletionObserver->SetPrevious(mDeletionObserver);
+  }
+  mDeletionObserver = aDeletionObserver;
+}