Bug 503943, add mouse capturing api to elements, remove capturing from views, r=roc,sr=smaug
authorNeil Deakin <neil@mozilla.com>
Sun, 13 Sep 2009 09:13:16 -0400
changeset 32435 eda2433181c909dadecc22e4c2210c9fca39d782
parent 32434 8afb652052039e3475d40b01594b61987cbf0e68
child 32436 40811b076d515f369ed6b142af845261eb7f903a
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, smaug
bugs503943
milestone1.9.3a1pre
Bug 503943, add mouse capturing api to elements, remove capturing from views, r=roc,sr=smaug
content/base/src/nsDocument.cpp
content/base/src/nsGenericElement.cpp
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
content/html/content/src/nsHTMLFormElement.cpp
dom/interfaces/core/nsIDOMNSDocument.idl
dom/interfaces/core/nsIDOMNSElement.idl
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/forms/nsListControlFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIFrame.h
layout/generic/nsSelection.cpp
layout/generic/test/test_bug470212.html
layout/xul/base/src/nsResizerFrame.cpp
layout/xul/base/src/nsSliderFrame.cpp
layout/xul/base/src/nsSliderFrame.h
layout/xul/base/src/nsSplitterFrame.cpp
layout/xul/base/src/nsSplitterFrame.h
layout/xul/base/src/nsTitleBarFrame.cpp
layout/xul/base/src/nsTitleBarFrame.h
layout/xul/base/src/nsXULPopupManager.cpp
toolkit/content/tests/widgets/Makefile.in
toolkit/content/tests/widgets/test_mousecapture.xul
toolkit/content/tests/widgets/test_scale.xul
view/public/nsIViewManager.h
view/public/nsIViewObserver.h
view/src/nsView.cpp
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/src/xpwidgets/nsBaseDragService.cpp
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2768,16 +2768,28 @@ nsDocument::MatchClassNames(nsIContent* 
 // static
 void
 nsDocument::DestroyClassNameArray(void* aData)
 {
   ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
   delete info;
 }
 
+NS_IMETHODIMP
+nsDocument::ReleaseCapture()
+{
+  // only release the capture if the caller can access it. This prevents a
+  // page from stopping a scrollbar grab for example.
+  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(nsIPresShell::GetCapturingContent());
+  if (node && nsContentUtils::CanCallerAccess(node)) {
+    nsIPresShell::SetCapturingContent(nsnull, 0);
+  }
+  return NS_OK;
+}
+
 nsresult
 nsDocument::SetBaseURI(nsIURI* aURI)
 {
   nsresult rv = NS_OK;
 
   if (aURI) {
     rv = nsContentUtils::GetSecurityManager()->
       CheckLoadURIWithPrincipal(NodePrincipal(), aURI,
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1079,16 +1079,39 @@ nsNSElementTearoff::GetClassList(nsIDOMD
     NS_ENSURE_TRUE(slots->mClassList, NS_ERROR_OUT_OF_MEMORY);
   }
 
   NS_ADDREF(*aResult = slots->mClassList);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNSElementTearoff::SetCapture(PRBool aRetargetToElement)
+{
+  // If there is already an active capture, ignore this request. This would
+  // occur if a splitter, frame resizer, etc had already captured and we don't
+  // want to override those.
+  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(nsIPresShell::GetCapturingContent());
+  if (node)
+    return NS_OK;
+
+  nsIPresShell::SetCapturingContent(mContent, aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSElementTearoff::ReleaseCapture()
+{
+  if (nsIPresShell::GetCapturingContent() == mContent) {
+    nsIPresShell::SetCapturingContent(nsnull, 0);
+  }
+  return NS_OK;
+}
+
 //----------------------------------------------------------------------
 
 
 NS_IMPL_CYCLE_COLLECTION_1(nsNSElementTearoff, mContent)
 
 NS_INTERFACE_MAP_BEGIN(nsNSElementTearoff)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNSElement)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsNSElementTearoff)
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -2736,29 +2736,19 @@ nsEventStateManager::PostHandleEvent(nsP
   nsRefPtr<nsPresContext> presContext = aPresContext;
   nsresult ret = NS_OK;
 
   switch (aEvent->message) {
   case NS_MOUSE_BUTTON_DOWN:
     {
       if (static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton &&
           !mNormalLMouseEventInProcess) {
-        //Our state is out of whack.  We got a mouseup while still processing
-        //the mousedown.  Kill View-level mouse capture or it'll stay stuck
-        if (aView) {
-          nsIViewManager* viewMan = aView->GetViewManager();
-          if (viewMan) {
-            nsIView* grabbingView;
-            viewMan->GetMouseEventGrabber(grabbingView);
-            if (grabbingView == aView) {
-              PRBool result;
-              viewMan->GrabMouseEvents(nsnull, result);
-            }
-          }
-        }
+        // We got a mouseup event while a mousedown event was being processed.
+        // Make sure that the capturing content is cleared.
+        nsIPresShell::SetCapturingContent(nsnull, 0);
         break;
       }
 
       if (nsEventStatus_eConsumeNoDefault != *aStatus) {
         nsCOMPtr<nsIContent> newFocus;
         nsIContent* activeContent = nsnull;
         PRBool suppressBlur = PR_FALSE;
         if (mCurrentTarget) {
@@ -2853,27 +2843,19 @@ nsEventStateManager::PostHandleEvent(nsP
       if (!mCurrentTarget) {
         nsIFrame* targ;
         GetEventTarget(&targ);
       }
       if (mCurrentTarget) {
         ret =
           CheckForAndDispatchClick(presContext, (nsMouseEvent*)aEvent, aStatus);
       }
+
       nsIPresShell *shell = presContext->GetPresShell();
       if (shell) {
-        nsIViewManager* viewMan = shell->GetViewManager();
-        if (viewMan) {
-          nsIView* grabbingView = nsnull;
-          viewMan->GetMouseEventGrabber(grabbingView);
-          if (grabbingView == aView) {
-            PRBool result;
-            viewMan->GrabMouseEvents(nsnull, result);
-          }
-        }
         nsCOMPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
         frameSelection->SetMouseDownState(PR_FALSE);
       }
     }
     break;
   case NS_MOUSE_SCROLL:
   case NS_MOUSE_PIXEL_SCROLL:
     {
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -406,37 +406,48 @@ protected:
   static void sClickHoldCallback ( nsITimer* aTimer, void* aESM ) ;
   
   nsCOMPtr<nsITimer> mClickHoldTimer;
 #endif
 
   static PRInt32 sUserInputEventDepth;
 };
 
-
+/**
+ * This class is used while processing real user input. During this time, popups
+ * are allowed. For mousedown events, mouse capturing is also permitted.
+ */
 class nsAutoHandlingUserInputStatePusher
 {
 public:
-  nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput)
-    : mIsHandlingUserInput(aIsHandlingUserInput)
+  nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput, PRBool aIsMouseDown)
+    : mIsHandlingUserInput(aIsHandlingUserInput), mIsMouseDown(aIsMouseDown)
   {
     if (aIsHandlingUserInput) {
       nsEventStateManager::StartHandlingUserInput();
+      if (aIsMouseDown) {
+        nsIPresShell::SetCapturingContent(nsnull, 0);
+        nsIPresShell::AllowMouseCapture(PR_TRUE);
+      }
     }
   }
 
   ~nsAutoHandlingUserInputStatePusher()
   {
     if (mIsHandlingUserInput) {
       nsEventStateManager::StopHandlingUserInput();
+      if (mIsMouseDown) {
+        nsIPresShell::AllowMouseCapture(PR_FALSE);
+      }
     }
   }
 
 protected:
   PRBool mIsHandlingUserInput;
+  PRBool mIsMouseDown;
 
 private:
   // Hide so that this class can only be stack-allocated
   static void* operator new(size_t /*size*/) CPP_THROW_NEW { return nsnull; }
   static void operator delete(void* /*memory*/) {}
 };
 
 #endif // nsEventStateManager_h__
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -1134,17 +1134,17 @@ nsHTMLFormElement::SubmitSubmission(nsIF
   //
   // Submit
   //
   nsCOMPtr<nsIDocShell> docShell;
 
   {
     nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
 
-    nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput);
+    nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
 
     rv = aFormSubmission->SubmitTo(actionURI, target, this, linkHandler,
                                    getter_AddRefs(docShell),
                                    getter_AddRefs(mSubmittingRequest));
   }
 
   NS_ENSURE_SUBMIT_SUCCESS(rv);
 
--- a/dom/interfaces/core/nsIDOMNSDocument.idl
+++ b/dom/interfaces/core/nsIDOMNSDocument.idl
@@ -38,17 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIBoxObject;
 interface nsIDOMLocation;
 
-[scriptable, uuid(09a439ad-4079-46d5-a050-4d7015d1a108)]
+[scriptable, uuid(B7E9211B-F29F-4E2D-9762-6BCBC64E5C05)]
 interface nsIDOMNSDocument : nsISupports
 {
   readonly attribute DOMString      characterSet;
            attribute DOMString      dir;
 
   readonly attribute nsIDOMLocation location;
 
            attribute DOMString      title;
@@ -86,9 +86,15 @@ interface nsIDOMNSDocument : nsISupports
   *
   * Callers from XUL documents should wait until the onload event has fired
   * before calling this method.
   *
   * <a href="http://dev.w3.org/cvsweb/~checkout~/csswg/cssom/Overview.html?content-type=text/html;%20charset=utf-8#documentlayout-elementfrompoint">preliminary spec</a>
   */
   nsIDOMElement             elementFromPoint(in long x, in long y);
 
+  /**
+   * Release the current mouse capture if it is on an element within this
+   * document.
+   */
+  void releaseCapture();
+
 };
--- a/dom/interfaces/core/nsIDOMNSElement.idl
+++ b/dom/interfaces/core/nsIDOMNSElement.idl
@@ -34,17 +34,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(df86b1a8-02c3-47be-a76b-856620f925df)]
+[scriptable, uuid(FA8D7AF8-C208-4564-A0CD-346C345711F0)]
 interface nsIDOMNSElement : nsISupports
 {
   /*
    * Retrieve elements matching all classes listed in a
    * space-separated string.
    *
    * See <http://whatwg.org/specs/web-apps/current-work/>
    */
@@ -147,9 +147,25 @@ interface nsIDOMNSElement : nsISupports
    * Returns a live nsIDOMNodeList of the current child elements.
    */
   readonly attribute nsIDOMNodeList children;
 
   /**
    * Returns a DOMTokenList object reflecting the class attribute.
    */
   readonly attribute nsIDOMDOMTokenList classList;
+
+  /**
+   * Set this during a mousedown event to grab and retarget all mouse events
+   * to this element until the mouse button is released or releaseCapture is
+   * called. If retargetToElement is true, then all events are targetted at
+   * this element. If false, events can also fire at descendants of this
+   * element.
+   * 
+   */
+  void setCapture([optional] in boolean retargetToElement);
+
+  /**
+   * If this element has captured the mouse, release the capture. If another
+   * element has captured the mouse, this method has no effect.
+   */
+  void releaseCapture();
 };
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -99,16 +99,33 @@ class gfxContext;
 class nsPIDOMEventTarget;
 class nsIDOMEvent;
 class nsDisplayList;
 class nsDisplayListBuilder;
 
 typedef short SelectionType;
 typedef PRUint32 nsFrameState;
 
+// Flags to pass to SetCapturingContent
+//
+// when assigning capture, ignore whether capture is allowed or not
+#define CAPTURE_IGNOREALLOWED 1
+// true if events should be targeted at the capturing content or its children
+#define CAPTURE_RETARGETTOELEMENT 2
+
+typedef struct CapturingContentInfo {
+  // capture should only be allowed during a mousedown event
+  PRPackedBool mAllowed;
+  PRPackedBool mRetargetToElement;
+  nsIContent* mContent;
+
+  CapturingContentInfo() :
+    mAllowed(PR_FALSE), mRetargetToElement(PR_FALSE), mContent(nsnull) { }
+} CapturingContentInfo;
+
 // eba51d41-68db-4dab-a57b-dc1a2704de87
 #define NS_IPRESSHELL_IID     \
 { 0xeba51d41, 0x68db, 0x4dab, \
   { 0xa5, 0x7b, 0xdc, 0x1a, 0x27, 0x04, 0xde, 0x87 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
@@ -852,16 +869,52 @@ public:
   {
     mObservesMutationsForPrint = aObserve;
   }
   PRBool ObservesNativeAnonMutationsForPrint()
   {
     return mObservesMutationsForPrint;
   }
 
+  // mouse capturing
+
+  static CapturingContentInfo gCaptureInfo;
+
+  /**
+   * When capturing content is set, it traps all mouse events and retargets
+   * them at this content node. If capturing is not allowed
+   * (gCaptureInfo.mAllowed is false), then capturing is not set. However, if
+   * the CAPTURE_IGNOREALLOWED flag is set, the allowed state is ignored and
+   * capturing is set regardless. To disable capture, pass null for the value
+   * of aContent.
+   *
+   * If CAPTURE_RETARGETTOELEMENT is set, all mouse events are targeted at
+   * aContent only. Otherwise, mouse events are targeted at aContent or its
+   * descendants. That is, descendants of aContent receive mouse events as
+   * they normally would, but mouse events outside of aContent are retargeted
+   * to aContent.
+   */
+  static void SetCapturingContent(nsIContent* aContent, PRUint8 aFlags);
+
+  /**
+   * Return the active content currently capturing the mouse if any.
+   */
+  static nsIContent* GetCapturingContent()
+  {
+    return gCaptureInfo.mContent;
+  }
+
+  /**
+   * Allow or disallow mouse capturing.
+   */
+  static void AllowMouseCapture(PRBool aAllowed)
+  {
+    gCaptureInfo.mAllowed = aAllowed;
+  }
+
 protected:
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   // these are the same Document and PresContext owned by the DocViewer.
   // we must share ownership.
   nsIDocument*              mDocument;      // [STRONG]
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -203,16 +203,17 @@
 #include "imgIEncoder.h"
 #include "gfxPlatform.h"
 
 #include "nsContentCID.h"
 static NS_DEFINE_CID(kCSSStyleSheetCID, NS_CSS_STYLESHEET_CID);
 static NS_DEFINE_IID(kRangeCID,     NS_RANGE_CID);
 
 PRBool nsIPresShell::gIsAccessibilityActive = PR_FALSE;
+CapturingContentInfo nsIPresShell::gCaptureInfo;
 
 // convert a color value to a string, in the CSS format #RRGGBB
 // *  - initially created for bugs 31816, 20760, 22963
 static void ColorToString(nscolor aColor, nsAutoString &aString);
 
 // Class ID's
 static NS_DEFINE_CID(kFrameSelectionCID, NS_FRAMESELECTION_CID);
 
@@ -792,16 +793,17 @@ public:
                                       nsIDOMEvent* aEvent,
                                       nsEventStatus* aStatus);
   NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
   NS_IMETHOD_(PRBool) IsVisible();
   NS_IMETHOD_(void) WillPaint();
   NS_IMETHOD_(void) InvalidateFrameForView(nsIView *view);
   NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                            PRBool aFlushOnHoverChange);
+  NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView);
 
   // caret handling
   NS_IMETHOD GetCaret(nsCaret **aOutCaret);
   NS_IMETHOD_(void) MaybeInvalidateCaretPosition();
   NS_IMETHOD SetCaretEnabled(PRBool aInEnable);
   NS_IMETHOD SetCaretReadOnly(PRBool aReadOnly);
   NS_IMETHOD GetCaretEnabled(PRBool *aOutEnabled);
   NS_IMETHOD SetCaretVisibilityDuringSelection(PRBool aVisibility);
@@ -4372,16 +4374,51 @@ PresShell::DispatchSynthMouseMove(nsGUIE
   if (aFlushOnHoverChange &&
       hoverGenerationBefore != mFrameConstructor->GetHoverGeneration()) {
     // Flush so that the resulting reflow happens now so that our caller
     // can suppress any synthesized mouse moves caused by that reflow.
     FlushPendingNotifications(Flush_Layout);
   }
 }
 
+NS_IMETHODIMP_(void)
+PresShell::ClearMouseCapture(nsIView* aView)
+{
+  if (gCaptureInfo.mContent) {
+    if (aView) {
+      // if a view was specified, ensure that the captured content
+      // is within this view
+      nsIFrame* frame = GetPrimaryFrameFor(gCaptureInfo.mContent);
+      if (frame) {
+        nsIView* view = frame->GetClosestView();
+        while (view) {
+          if (view == aView) {
+            NS_RELEASE(gCaptureInfo.mContent);
+            // the view containing the captured content likely disappeared so
+            // disable capture for now.
+            gCaptureInfo.mAllowed = PR_FALSE;
+            break;
+          }
+
+          view = view->GetParent();
+        }
+        // return if the view wasn't found
+        return;
+      }
+    }
+
+    NS_RELEASE(gCaptureInfo.mContent);
+  }
+
+  // disable mouse capture until the next mousedown as a dialog has opened
+  // or a drag has started. Otherwise, someone could start capture during
+  // the modal dialog or drag.
+  gCaptureInfo.mAllowed = PR_FALSE;
+}
+
 NS_IMETHODIMP
 PresShell::DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& aOutValue)
 {
   aOutValue.Truncate();
   
   if (!mDocument) return NS_ERROR_FAILURE;
 
   nsresult rv;
@@ -5696,16 +5733,32 @@ PresShell::PaintDefaultBackground(nsIVie
   nscolor bgcolor = NS_ComposeColors(ComputeBackstopColor(aView),
                                      mCanvasBackgroundColor);
 
   aRenderingContext->SetColor(bgcolor);
   aRenderingContext->FillRect(aDirtyRect);
   return NS_OK;
 }
 
+// static
+void
+nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
+{
+  NS_IF_RELEASE(gCaptureInfo.mContent);
+
+  // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED flag
+  // is used
+  if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed) {
+    if (aContent) {
+      NS_ADDREF(gCaptureInfo.mContent = aContent);
+    }
+    gCaptureInfo.mRetargetToElement = (aFlags & CAPTURE_RETARGETTOELEMENT) != 0;
+  }
+}
+
 nsIFrame*
 PresShell::GetCurrentEventFrame()
 {
   if (NS_UNLIKELY(mIsDestroying)) {
     return nsnull;
   }
     
   if (!mCurrentEventFrame && mCurrentEventContent) {
@@ -5852,50 +5905,59 @@ PresShell::HandleEvent(nsIView         *
 #ifdef ACCESSIBILITY
   if (aEvent->eventStructType == NS_ACCESSIBLE_EVENT) {
     // Accessibility events come through OS requests and not from scripts,
     // so it is safe to handle here
     return HandleEventInternal(aEvent, aView, aEventStatus);
   }
 #endif
 
+  nsCOMPtr<nsIDocument> retargetEventDoc;
   // key and IME events must be targeted at the presshell for the focused frame
-  if (!sDontRetargetEvents && NS_IsEventTargetedAtFocusedWindow(aEvent)) {
-    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
-    if (!fm)
-      return NS_ERROR_FAILURE;
-
-    nsCOMPtr<nsIDOMWindow> window;
-    fm->GetFocusedWindow(getter_AddRefs(window));
-
-    // if there is no focused frame, there isn't anything to fire a key event
-    // at so just return
-    nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(window);
-    if (!piWindow)
-      return NS_OK;
-
-    nsCOMPtr<nsIDocument> doc(do_QueryInterface(piWindow->GetExtantDocument()));    
-    if (!doc)
-      return NS_OK;
-
-    nsIPresShell *presShell = doc->GetPrimaryShell();
-    if (!presShell)
-      return NS_OK;
-
-    if (presShell != this) {
-      nsCOMPtr<nsIViewObserver> viewObserver = do_QueryInterface(presShell);
-      if (!viewObserver)
-        return NS_ERROR_FAILURE;
-
-      nsIView *view;
-      presShell->GetViewManager()->GetRootView(view);
-      sDontRetargetEvents = PR_TRUE;
-      nsresult rv = viewObserver->HandleEvent(view, aEvent, aEventStatus);
-      sDontRetargetEvents = PR_FALSE;
-      return rv;
+  if (!sDontRetargetEvents) {
+    if (NS_IsEventTargetedAtFocusedWindow(aEvent)) {
+      nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+      if (!fm)
+         return NS_ERROR_FAILURE;
+ 
+      nsCOMPtr<nsIDOMWindow> window;
+      fm->GetFocusedWindow(getter_AddRefs(window));
+
+      // if there is no focused frame, there isn't anything to fire a key event
+      // at so just return
+      nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(window);
+      if (!piWindow)
+        return NS_OK;
+
+      retargetEventDoc = do_QueryInterface(piWindow->GetExtantDocument());
+      if (!retargetEventDoc)
+        return NS_OK;
+    } else if (NS_IS_MOUSE_EVENT(aEvent) && GetCapturingContent()) {
+      // if the mouse is being captured then retarget the mouse event at the
+      // document that is being captured.
+      retargetEventDoc = gCaptureInfo.mContent->GetCurrentDoc();
+    }
+
+    if (retargetEventDoc) {
+      nsIPresShell* presShell = retargetEventDoc->GetPrimaryShell();
+      if (!presShell)
+        return NS_OK;
+
+      if (presShell != this) {
+        nsCOMPtr<nsIViewObserver> viewObserver = do_QueryInterface(presShell);
+        if (!viewObserver)
+          return NS_ERROR_FAILURE;
+
+        nsIView *view;
+        presShell->GetViewManager()->GetRootView(view);
+        sDontRetargetEvents = PR_TRUE;
+        nsresult rv = viewObserver->HandleEvent(view, aEvent, aEventStatus);
+        sDontRetargetEvents = PR_FALSE;
+        return rv;
+      }
     }
   }
 
   // Check for a theme change up front, since the frame type is irrelevant
   if (aEvent->message == NS_THEMECHANGED && mPresContext) {
     mPresContext->ThemeChanged();
     return NS_OK;
   }
@@ -5936,18 +5998,51 @@ PresShell::HandleEvent(nsIView         *
       }
     }
     if (event && !mDelayedEvents.AppendElement(event)) {
       delete event;
     }
     return NS_OK;
   }
 
+  PRBool getDescendantPoint = PR_TRUE;
   nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
 
+  if (NS_IS_MOUSE_EVENT(aEvent) && GetCapturingContent()) {
+    // if a node is capturing the mouse, get the frame for the capturing
+    // content and use that instead. However, if the content has no parent,
+    // such as the root frame, get the parent canvas frame instead. This
+    // ensures that positioned frames are included when hit-testing.
+    nsIContent* capturingContent = gCaptureInfo.mContent;
+    frame = GetPrimaryFrameFor(capturingContent);
+    if (frame) {
+      getDescendantPoint = !gCaptureInfo.mRetargetToElement;
+      if (!capturingContent->GetParent()) {
+        frame = frame->GetParent();
+      }
+      else {
+        // special case for <select> as it needs to capture on the dropdown list.
+        if (capturingContent->Tag() == nsGkAtoms::select &&
+            capturingContent->IsNodeOfType(nsINode::eHTML)) {
+          nsIFrame* childframe = frame->GetChildList(nsGkAtoms::selectPopupList).FirstChild();
+          if (childframe) {
+            frame = childframe;
+          }
+        }
+
+        // if the frame is a scrolling frame, get the inner scrolled frame instead.
+        nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
+        if (scrollFrame) {
+          frame = scrollFrame->GetScrolledFrame();
+        }
+      }
+      aView = frame->GetClosestView();
+    }
+  }
+
   PRBool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
 
   // if this event has no frame, we need to retarget it at a parent
   // view that has a frame.
   if (!frame &&
       (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) ||
        NS_IS_IME_EVENT(aEvent))) {
     nsIView* targetView = aView;
@@ -5990,27 +6085,29 @@ PresShell::HandleEvent(nsIView         *
             frame = popup;
             break;
           }
         }
       }
 #endif
     }
 
-    nsPoint eventPoint
-        = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
-    nsIFrame* targetFrame;
-    {
-      nsAutoDisableGetUsedXAssertions disableAssert;
-      PRBool ignoreRootScrollFrame = PR_FALSE;
-      if (aEvent->eventStructType == NS_MOUSE_EVENT) {
-        ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
+    nsIFrame* targetFrame = nsnull;
+    if (getDescendantPoint) {
+      nsPoint eventPoint
+          = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
+      {
+        nsAutoDisableGetUsedXAssertions disableAssert;
+        PRBool ignoreRootScrollFrame = PR_FALSE;
+        if (aEvent->eventStructType == NS_MOUSE_EVENT) {
+          ignoreRootScrollFrame = static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame;
+        }
+        targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
+                                                      PR_FALSE, ignoreRootScrollFrame);
       }
-      targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint,
-                                                    PR_FALSE, ignoreRootScrollFrame);
     }
 
     if (targetFrame) {
       PresShell* shell =
           static_cast<PresShell*>(targetFrame->PresContext()->PresShell());
       if (shell != this) {
         // Handle the event in the correct shell.
         // Prevent deletion until we're done with event handling (bug 336582).
@@ -6280,17 +6377,18 @@ PresShell::HandleEventInternal(nsEvent* 
         return NS_OK;
       }
       if (me->context == nsMouseEvent::eContextMenuKey &&
           !AdjustContextMenuKeyEvent(me)) {
         return NS_OK;
       }
     }                                
 
-    nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput);
+    nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
+                                                          aEvent->message == NS_MOUSE_BUTTON_DOWN);
 
     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);
@@ -6326,16 +6424,21 @@ PresShell::HandleEventInternal(nsEvent* 
       // 3. Give event to event manager for post event state changes and
       //    generation of synthetic events.
       if (!mIsDestroying && NS_SUCCEEDED(rv)) {
         rv = manager->PostHandleEvent(mPresContext, aEvent,
                                       GetCurrentEventFrame(), aStatus,
                                       weakView.GetView());
       }
     }
+
+    if (aEvent->message == NS_MOUSE_BUTTON_UP) {
+      // reset the capturing content now that the mouse button is up
+      SetCapturingContent(nsnull, 0);
+    }
   }
   return rv;
 }
 
 // Dispatch event to content only (NOT full processing)
 // See also HandleEventWithTarget which does full event processing.
 NS_IMETHODIMP
 PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent, nsEvent* aEvent,
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -1028,38 +1028,33 @@ nsListControlFrame::CaptureMouseEvents(P
     return;
   
   nsIView* view = GetScrolledFrame()->GetView();
 
   NS_ASSERTION(view, "no view???");
   if (NS_UNLIKELY(!view))
     return;
 
-  nsIViewManager* viewMan = view->GetViewManager();
-  if (viewMan) {
-    PRBool result;
-    // It's not clear why we don't have the widget capture mouse events here.
-    if (aGrabMouseEvents) {
-      viewMan->GrabMouseEvents(view, result);
-    } else {
-      nsIView* curGrabber;
-      viewMan->GetMouseEventGrabber(curGrabber);
-      PRBool dropDownIsHidden = PR_FALSE;
-      if (IsInDropDownMode()) {
-        dropDownIsHidden = !mComboboxFrame->IsDroppedDown();
-      }
-      if (curGrabber == view || dropDownIsHidden) {
-        // only unset the grabber if *we* are the ones doing the grabbing
-        // (or if the dropdown is hidden, in which case NO-ONE should be
-        // grabbing anything
-        // it could be a scrollbar inside this listbox which is actually grabbing
-        // This shouldn't be necessary. We should simply ensure that events targeting
-        // scrollbars are never visible to DOM consumers.
-        viewMan->GrabMouseEvents(nsnull, result);
-      }
+  if (aGrabMouseEvents) {
+    nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED);
+  } else {
+    nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
+
+    PRBool dropDownIsHidden = PR_FALSE;
+    if (IsInDropDownMode()) {
+      dropDownIsHidden = !mComboboxFrame->IsDroppedDown();
+    }
+    if (capturingContent == mContent || dropDownIsHidden) {
+      // only clear the capturing content if *we* are the ones doing the
+      // capturing (or if the dropdown is hidden, in which case NO-ONE should
+      // be capturing anything - it could be a scrollbar inside this listbox
+      // which is actually grabbing
+      // This shouldn't be necessary. We should simply ensure that events targeting
+      // scrollbars are never visible to DOM consumers.
+      nsIPresShell::SetCapturingContent(nsnull, 0);
     }
   }
 }
 
 //---------------------------------------------------------
 NS_IMETHODIMP 
 nsListControlFrame::HandleEvent(nsPresContext* aPresContext, 
                                 nsGUIEvent*    aEvent,
@@ -2117,21 +2112,17 @@ nsListControlFrame::FireMenuItemActiveEv
 
 nsresult
 nsListControlFrame::GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent, 
                                          PRInt32&     aCurIndex)
 {
   if (IgnoreMouseEventForSelection(aMouseEvent))
     return NS_ERROR_FAILURE;
 
-  nsIView* view = GetScrolledFrame()->GetView();
-  nsIViewManager* viewMan = view->GetViewManager();
-  nsIView* curGrabber;
-  viewMan->GetMouseEventGrabber(curGrabber);
-  if (curGrabber != view) {
+  if (nsIPresShell::GetCapturingContent() != mContent) {
     // If we're not capturing, then ignore movement in the border
     nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(aMouseEvent, this);
     nsRect borderInnerEdge = GetScrollableView()->View()->GetBounds();
     if (!borderInnerEdge.Contains(pt)) {
       return NS_ERROR_FAILURE;
     }
   }
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -50,16 +50,17 @@
 #include "nsIContent.h"
 #include "nsContentUtils.h"
 #include "nsIAtom.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsStyleContext.h"
 #include "nsIView.h"
 #include "nsIViewManager.h"
+#include "nsIScrollableView.h"
 #include "nsIScrollableFrame.h"
 #include "nsPresContext.h"
 #include "nsCRT.h"
 #include "nsGUIEvent.h"
 #include "nsIDOMEvent.h"
 #include "nsPLDOMEvent.h"
 #include "nsStyleConsts.h"
 #include "nsIPresShell.h"
@@ -738,28 +739,27 @@ nsFrame::GetAdditionalChildListName(PRIn
 
 nsFrameList
 nsFrame::GetChildList(nsIAtom* aListName) const
 {
   return nsFrameList::EmptyList();
 }
 
 static nsIFrame*
-GetActiveSelectionFrame(nsIFrame* aFrame)
-{
-  nsIView* mouseGrabber;
-  aFrame->PresContext()->GetPresShell()->
-    GetViewManager()->GetMouseEventGrabber(mouseGrabber);
-  if (mouseGrabber) {
-    nsIFrame* activeFrame = nsLayoutUtils::GetFrameFor(mouseGrabber);
-    if (activeFrame) {
-      return activeFrame;
+GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
+{
+  nsIPresShell* shell = aPresContext->GetPresShell(); 
+  if (shell) {
+    nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
+    if (capturingContent) {
+      nsIFrame* activeFrame = shell->GetPrimaryFrameFor(capturingContent);
+      return activeFrame ? activeFrame : aFrame;
     }
   }
-    
+
   return aFrame;
 }
 
 PRInt16
 nsFrame::DisplaySelection(nsPresContext* aPresContext, PRBool isOkToTurnOn)
 {
   PRInt16 selType = nsISelectionController::SELECTION_OFF;
 
@@ -1902,18 +1902,33 @@ nsFrame::HandlePress(nsPresContext* aPre
   // check for select: none
   if (!selectable)
     return NS_OK;
 
   // When implementing NS_STYLE_USER_SELECT_ELEMENT, NS_STYLE_USER_SELECT_ELEMENTS and
   // NS_STYLE_USER_SELECT_TOGGLE, need to change this logic
   PRBool useFrameSelection = (selectStyle == NS_STYLE_USER_SELECT_TEXT);
 
-  if (!IsMouseCaptured(aPresContext))
-    CaptureMouse(aPresContext, PR_TRUE);
+  // If the mouse is dragged outside the nearest enclosing scrollable area
+  // while making a selection, the area will be scrolled. To do this, capture
+  // the mouse on the nearest scrollable frame. If there isn't a scrollable
+  // frame, or something else is already capturing the mouse, there's no
+  // reason to capture.
+  if (!nsIPresShell::GetCapturingContent()) {
+    nsIFrame* checkFrame = this;
+    nsIScrollableFrame *scrollFrame = nsnull;
+    while (checkFrame) {
+      scrollFrame = do_QueryFrame(checkFrame);
+      if (scrollFrame) {
+        nsIPresShell::SetCapturingContent(checkFrame->GetContent(), CAPTURE_IGNOREALLOWED);
+        break;
+      }
+      checkFrame = checkFrame->GetParent();
+    }
+  }
 
   // XXX This is screwy; it really should use the selection frame, not the
   // event frame
   const nsFrameSelection* frameselection = nsnull;
   if (useFrameSelection)
     frameselection = GetConstFrameSelection();
   else
     frameselection = shell->ConstFrameSelection();
@@ -2178,39 +2193,16 @@ nsFrame::PeekBackwardAndForward(nsSelect
                                    nsFrameSelection::HINTLEFT);
   if (NS_FAILED(rv))
     return rv;
 
   // maintain selection
   return frameSelection->MaintainSelection(aAmountBack);
 }
 
-// Figure out which view we should point capturing at, given that drag started
-// in this frame.
-static nsIView* GetNearestCapturingView(nsIFrame* aFrame) {
-  nsIView* view = nsnull;
-  while (!(view = aFrame->GetMouseCapturer()) && aFrame->GetParent()) {
-    aFrame = aFrame->GetParent();
-  }
-  if (!view) {
-    // Use the root view. The root frame always has the root view.
-    view = aFrame->GetView();
-  }
-  NS_ASSERTION(view, "No capturing view found");
-  return view;
-}
-
-nsIFrame* nsFrame::GetNearestCapturingFrame(nsIFrame* aFrame) {
-  nsIFrame* captureFrame = aFrame;
-  while (captureFrame && !captureFrame->GetMouseCapturer()) {
-    captureFrame = captureFrame->GetParent();
-  }
-  return captureFrame;
-}
-
 NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext, 
                                   nsGUIEvent*     aEvent,
                                   nsEventStatus*  aEventStatus)
 {
   PRBool  selectable;
   PRUint8 selectStyle;
   IsSelectable(&selectable, &selectStyle);
   // XXX Do we really need to exclude non-selectable content here?
@@ -2225,23 +2217,16 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPres
 
   nsCOMPtr<nsFrameSelection> frameselection = GetFrameSelection();
   PRBool mouseDown = frameselection->GetMouseDownState();
   if (!mouseDown)
     return NS_OK;
 
   frameselection->StopAutoScrollTimer();
 
-  // If we have capturing view, it must be ensured that |this| doesn't 
-  // get deleted during HandleDrag.
-  nsWeakFrame weakFrame = GetNearestCapturingView(this) ? this : nsnull;
-#ifdef NS_DEBUG
-  PRBool frameAlive = weakFrame.IsAlive();
-#endif
-
   // Check if we are dragging in a table cell
   nsCOMPtr<nsIContent> parentContent;
   PRInt32 contentOffset;
   PRInt32 target;
   nsMouseEvent *me = (nsMouseEvent *)aEvent;
   nsresult result;
   result = GetDataForTableSelection(frameselection, presShell, me,
                                     getter_AddRefs(parentContent),
@@ -2249,32 +2234,39 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsPres
 
   if (NS_SUCCEEDED(result) && parentContent) {
     frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
   } else {
     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
     frameselection->HandleDrag(this, pt);
   }
 
-  if (weakFrame) {
-    nsIView* captureView = GetNearestCapturingView(this);
-    if (captureView) {
+  // get the nearest scrollframe
+  nsIFrame* checkFrame = this;
+  nsIScrollableFrame *scrollFrame = nsnull;
+  while (checkFrame) {
+    scrollFrame = do_QueryFrame(checkFrame);
+    if (scrollFrame) {
+      break;
+    }
+    checkFrame = checkFrame->GetParent();
+  }
+
+  if (scrollFrame) {
+    nsIView* capturingView = scrollFrame->GetScrollableView()->View();
+    if (capturingView) {
       // Get the view that aEvent->point is relative to. This is disgusting.
       nsIView* eventView = nsnull;
       nsPoint pt = nsLayoutUtils::GetEventCoordinatesForNearestView(aEvent, this,
                                                                     &eventView);
-      nsPoint capturePt = pt + eventView->GetOffsetTo(captureView);
-      frameselection->StartAutoScrollTimer(captureView, capturePt, 30);
+      nsPoint capturePt = pt + eventView->GetOffsetTo(capturingView);
+      frameselection->StartAutoScrollTimer(capturingView, capturePt, 30);
     }
   }
-#ifdef NS_DEBUG
-  if (frameAlive && !weakFrame.IsAlive()) {
-    NS_WARNING("nsFrame deleted during nsFrame::HandleDrag.");
-  }
-#endif
+
   return NS_OK;
 }
 
 /**
  * This static method handles part of the nsFrame::HandleRelease in a way
  * which doesn't rely on the nsFrame object to stay alive.
  */
 static nsresult
@@ -2337,21 +2329,21 @@ HandleFrameSelection(nsFrameSelection*  
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
                                      nsGUIEvent*    aEvent,
                                      nsEventStatus* aEventStatus)
 {
-  nsIFrame* activeFrame = GetActiveSelectionFrame(this);
+  nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
 
   // We can unconditionally stop capturing because
   // we should never be capturing when the mouse button is up
-  CaptureMouse(aPresContext, PR_FALSE);
+  nsIPresShell::SetCapturingContent(nsnull, 0);
 
   PRBool selectionOff =
     (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
 
   nsRefPtr<nsFrameSelection> frameselection;
   ContentOffsets offsets;
   nsCOMPtr<nsIContent> parentContent;
   PRInt32 contentOffsetForTableSel = 0;
@@ -5926,61 +5918,16 @@ nsFrame::GetFirstLeaf(nsPresContext* aPr
   while (1){
     child = child->GetFirstChild(nsnull);
     if (!child)
       return;//nothing to do
     *aFrame = child;
   }
 }
 
-NS_IMETHODIMP
-nsFrame::CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents)
-{
-  // get its view
-  nsIView* view = GetNearestCapturingView(this);
-  if (!view) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsIViewManager* viewMan = view->GetViewManager();
-  if (!viewMan) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (aGrabMouseEvents) {
-    PRBool result;
-    viewMan->GrabMouseEvents(view, result);
-  } else {
-    PRBool result;
-    viewMan->GrabMouseEvents(nsnull, result);
-  }
-
-  return NS_OK;
-}
-
-PRBool
-nsFrame::IsMouseCaptured(nsPresContext* aPresContext)
-{
-    // get its view
-  nsIView* view = GetNearestCapturingView(this);
-  
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-
-    if (viewMan) {
-        nsIView* grabbingView;
-        viewMan->GetMouseEventGrabber(grabbingView);
-        if (grabbingView == view)
-          return PR_TRUE;
-    }
-  }
-
-  return PR_FALSE;
-}
-
 nsresult
 nsIFrame::SetProperty(nsIAtom*           aPropName,
                       void*              aPropValue,
                       NSPropertyDtorFunc aPropDtorFunc,
                       void*              aDtorData)
 {
   return PresContext()->PropertyTable()->
     SetProperty(this, aPropName, aPropValue, aPropDtorFunc, aDtorData);
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -210,24 +210,16 @@ public:
 
   static nsresult  GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
                                         nsPeekOffsetStruct *aPos, 
                                         nsIFrame *aBlockFrame, 
                                         PRInt32 aLineStart, 
                                         PRInt8 aOutSideLimit
                                         );
 
-  /**
-   * Find the nearest frame with a mouse capturer. If no
-   * parent has mouse capture this will return null.
-   * @param aFrame Frame drag began in.
-   * @return Nearest capturing frame.
-   */
-  static nsIFrame* GetNearestCapturingFrame(nsIFrame* aFrame);
-
   NS_IMETHOD  CharacterDataChanged(CharacterDataChangeInfo* aInfo);
   NS_IMETHOD  AttributeChanged(PRInt32         aNameSpaceID,
                                nsIAtom*        aAttribute,
                                PRInt32         aModType);
   virtual nsSplittableType GetSplittableType() const;
   virtual nsIFrame* GetPrevContinuation() const;
   NS_IMETHOD  SetPrevContinuation(nsIFrame*);
   virtual nsIFrame* GetNextContinuation() const;
@@ -410,20 +402,16 @@ public:
                                         nsIFrame**      aProviderFrame,
                                         PRBool*         aIsChild);
 
   // incorporate the child overflow area into the parent overflow area
   // if the child does not have a overflow use the child area
   void ConsiderChildOverflow(nsRect&   aOverflowArea,
                              nsIFrame* aChildFrame);
 
-  //Mouse Capturing code used by the frames to tell the view to capture all the following events
-  NS_IMETHOD CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents);
-  PRBool   IsMouseCaptured(nsPresContext* aPresContext);
-
   virtual const void* GetStyleDataExternal(nsStyleStructID aSID) const;
 
 
 #ifdef NS_DEBUG
   /**
    * Tracing method that writes a method enter/exit routine to the
    * nspr log using the nsIFrame log module. The tracing is only
    * done when the NS_FRAME_TRACE_CALLS bit is set in the log module's
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -313,29 +313,16 @@ nsHTMLFramesetFrame::Init(nsIContent*   
     } else {
       break;
     }
   }
 
   nsPresContext* presContext = PresContext();
   nsIPresShell* shell = presContext->PresShell();
 
-  // create the view. a view is needed since it needs to be a mouse grabber
-  nsIViewManager* viewMan = shell->GetViewManager();
-
-  nsIView *parView = GetAncestorWithView()->GetView();
-  nsRect boundBox(0, 0, 0, 0); 
-  nsIView* view = viewMan->CreateView(boundBox, parView);
-  if (!view)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  // XXX Put it last in document order until we can do better
-  viewMan->InsertChild(parView, view, nsnull, PR_TRUE);
-  SetView(view);
-  
   nsFrameborder  frameborder = GetFrameBorder();
   PRInt32 borderWidth = GetBorderWidth(presContext, PR_FALSE);
   nscolor borderColor = GetBorderColor();
  
   // Get the rows= cols= data
   nsCOMPtr<nsIFrameSetElement> ourContent(do_QueryInterface(mContent));
   NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
   const nsFramesetSpec* rowSpecs = nsnull;
@@ -810,38 +797,16 @@ NS_METHOD nsHTMLFramesetFrame::HandleEve
     }
     *aEventStatus = nsEventStatus_eConsumeNoDefault;
   } else {
     *aEventStatus = nsEventStatus_eIgnore;
   }
   return NS_OK;
 }
 
-#if 0
-PRBool 
-nsHTMLFramesetFrame::IsGrabbingMouse()
-{
-  PRBool result = PR_FALSE;
-  nsIView* view = GetView();
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-    if (viewMan) {
-      nsIView* grabber;
-      viewMan->GetMouseEventGrabber(grabber);
-      if (grabber == view) {
-        // the nsFramesetBorderFrame has captured NS_MOUSE_DOWN
-        result = PR_TRUE;
-      }
-      NS_RELEASE(viewMan);
-    }
-  }
-  return result;
-}
-#endif
-
 NS_IMETHODIMP
 nsHTMLFramesetFrame::GetCursor(const nsPoint&    aPoint,
                                nsIFrame::Cursor& aCursor)
 {
   if (mDragger) {
     aCursor.mCursor = (mDragger->mVertical) ? NS_STYLE_CURSOR_EW_RESIZE : NS_STYLE_CURSOR_NS_RESIZE;
   } else {
     aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
@@ -1476,38 +1441,33 @@ nsHTMLFramesetFrame::StartMouseDrag(nsPr
                                     nsHTMLFramesetBorderFrame* aBorder, 
                                     nsGUIEvent*                aEvent)
 {
 #if 0
   PRInt32 index;
   IndexOf(aBorder, index);
   NS_ASSERTION((nsnull != aBorder) && (index >= 0), "invalid dragger");
 #endif
-  nsIView* view = GetView();
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-    if (viewMan) {
-      PRBool ignore;
-      viewMan->GrabMouseEvents(view, ignore);
-      mDragger = aBorder;
+
+  nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
 
-      mFirstDragPoint = aEvent->refPoint;
+  mDragger = aBorder;
+
+  mFirstDragPoint = aEvent->refPoint;
 
-      // Store the original frame sizes
-      if (mDragger->mVertical) {
-        mPrevNeighborOrigSize = mColSizes[mDragger->mPrevNeighbor];
-	mNextNeighborOrigSize = mColSizes[mDragger->mNextNeighbor];
-      } else {
-        mPrevNeighborOrigSize = mRowSizes[mDragger->mPrevNeighbor];
-	mNextNeighborOrigSize = mRowSizes[mDragger->mNextNeighbor];
-      }
+  // Store the original frame sizes
+  if (mDragger->mVertical) {
+    mPrevNeighborOrigSize = mColSizes[mDragger->mPrevNeighbor];
+    mNextNeighborOrigSize = mColSizes[mDragger->mNextNeighbor];
+  } else {
+    mPrevNeighborOrigSize = mRowSizes[mDragger->mPrevNeighbor];
+    mNextNeighborOrigSize = mRowSizes[mDragger->mNextNeighbor];
+  }
 
-      gDragInProgress = PR_TRUE;
-    }
-  }
+  gDragInProgress = PR_TRUE;
 }
   
 
 void
 nsHTMLFramesetFrame::MouseDrag(nsPresContext* aPresContext, 
                                nsGUIEvent*     aEvent)
 {
   PRInt32 change; // measured positive from left-to-right or top-to-bottom
@@ -1578,27 +1538,20 @@ nsHTMLFramesetFrame::MouseDrag(nsPresCon
       }
     }
   }
 }  
 
 void
 nsHTMLFramesetFrame::EndMouseDrag(nsPresContext* aPresContext)
 {
-  nsIView* view = GetView();
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-    if (viewMan) {
-      mDragger = nsnull;
-      PRBool ignore;
-      viewMan->GrabMouseEvents(nsnull, ignore);
-    }
-  }
+  nsIPresShell::SetCapturingContent(nsnull, 0);
+  mDragger = nsnull;
   gDragInProgress = PR_FALSE;
-}  
+}
 
 nsIFrame*
 NS_NewHTMLFramesetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
 #ifdef DEBUG
   const nsStyleDisplay* disp = aContext->GetStyleDisplay();
   NS_ASSERTION(!disp->IsAbsolutelyPositioned() && !disp->IsFloating(),
                "Framesets should not be positioned and should not float");
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -305,20 +305,16 @@ public:
   virtual nsIView* GetParentViewForChildFrame(nsIFrame* aFrame) const {
     return mInner.GetParentViewForChildFrame(aFrame);
   }
 
   virtual nsIFrame* GetContentInsertionFrame() {
     return mInner.GetScrolledFrame()->GetContentInsertionFrame();
   }
 
-  virtual nsIView* GetMouseCapturer() const {
-    return mInner.GetScrolledFrame()->GetView();
-  }
-
   virtual void InvalidateInternal(const nsRect& aDamageRect,
                                   nscoord aX, nscoord aY, nsIFrame* aForChild,
                                   PRUint32 aFlags);
 
   virtual PRBool NeedsView() { return PR_TRUE; }
   virtual PRBool DoesClipChildren() { return PR_TRUE; }
   virtual nsSplittableType GetSplittableType() const;
 
@@ -473,20 +469,16 @@ public:
   virtual nsIView* GetParentViewForChildFrame(nsIFrame* aFrame) const {
     return mInner.GetParentViewForChildFrame(aFrame);
   }
 
   virtual nsIFrame* GetContentInsertionFrame() {
     return mInner.GetScrolledFrame()->GetContentInsertionFrame();
   }
 
-  virtual nsIView* GetMouseCapturer() const {
-    return mInner.GetScrolledFrame()->GetView();
-  }
-
   virtual void InvalidateInternal(const nsRect& aDamageRect,
                                   nscoord aX, nscoord aY, nsIFrame* aForChild,
                                   PRUint32 aFlags);
 
   virtual PRBool NeedsView() { return PR_TRUE; }
   virtual PRBool DoesClipChildren() { return PR_TRUE; }
   virtual nsSplittableType GetSplittableType() const;
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -102,19 +102,20 @@ struct nsPeekOffsetStruct;
 struct nsPoint;
 struct nsRect;
 struct nsSize;
 struct nsMargin;
 struct CharacterDataChangeInfo;
 
 typedef class nsIFrame nsIBox;
 
+// 87F5B42A-507D-4707-976C-46819867BC63
 #define NS_IFRAME_IID \
-  { 0x7e9018b5, 0x5405, 0x4e2b, \
-    { 0x87, 0x67, 0xe2, 0xb4, 0xb1, 0x3e, 0xc1, 0x69 } }
+  { 0x87f5b42a, 0x507d, 0x4707, \
+    { 0x97, 0x6c, 0x46, 0x81, 0x98, 0x67, 0xbc, 0x63 } }
 
 /**
  * Indication of how the frame can be split. This is used when doing runaround
  * of floats, and when pulling up child frames from a next-in-flow.
  *
  * The choices are splittable, not splittable at all, and splittable in
  * a non-rectangular fashion. This last type only applies to block-level
  * elements, and indicates whether splitting can be used when doing runaround.
@@ -1728,24 +1729,16 @@ public:
    * have kids.  It could still have kids created via
    * nsIAnonymousContentCreator.  Returning true indicates that "normal"
    * (non-anonymous, XBL-bound, CSS generated content, etc) children should not
    * be constructed.
    */
   virtual PRBool IsLeaf() const;
 
   /**
-   * Does this frame want to capture the mouse when the user clicks in
-   * it or its children? If so, return the view which should be
-   * targeted for mouse capture. The view need not be this frame's view,
-   * it could be the view on a child.
-   */
-  virtual nsIView* GetMouseCapturer() const { return nsnull; }
-
-  /**
    * @param aFlags see InvalidateInternal below
    */
   void InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags);
 
   /**
    * Invalidate part of the frame by asking the view manager to repaint.
    * aDamageRect is allowed to extend outside the frame's bounds. We'll do the right
    * thing.
@@ -1950,24 +1943,16 @@ public:
    * example in nsIFrame code.
    */
   const nsFrameSelection* GetConstFrameSelection();
 
   /** EndSelection related calls
    */
 
   /**
-   *  Call to turn on/off mouseCapture at the view level. Needed by the ESM so
-   *  it must be in the public interface.
-   *  @param aPresContext presContext associated with the frame
-   *  @param aGrabMouseEvents PR_TRUE to enable capture, PR_FALSE to disable
-   */
-  NS_IMETHOD CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents) = 0;
-
-  /**
    *  called to find the previous/next character, word, or line  returns the actual 
    *  nsIFrame and the frame offset.  THIS DOES NOT CHANGE SELECTION STATE
    *  uses frame's begin selection state to start. if no selection on this frame will 
    *  return NS_ERROR_FAILURE
    *  @param aPOS is defined in nsFrameSelection
    */
   NS_IMETHOD PeekOffset(nsPeekOffsetStruct *aPos);
 
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -409,54 +409,25 @@ public:
   }
 
   virtual ~nsAutoScrollTimer()
   {
    if (mTimer)
        mTimer->Cancel();
   }
 
-  nsresult Start(nsPresContext *aPresContext, nsIView *aView, nsPoint &aPoint)
+  nsresult Start(nsPresContext *aPresContext, nsPoint &aPoint)
   {
     mPoint = aPoint;
 
     // Store the presentation context. The timer will be
     // stopped by the selection if the prescontext is destroyed.
     mPresContext = aPresContext;
 
-    // Store the content from the nearest capturing frame. If this returns null
-    // the capturing frame is the root.
-    nsIFrame* clientFrame = static_cast<nsIFrame*>(aView->GetClientData());
-    NS_ASSERTION(clientFrame, "Missing client frame");
-
-    nsIFrame* capturingFrame = nsFrame::GetNearestCapturingFrame(clientFrame);
-    NS_ASSERTION(!capturingFrame || capturingFrame->GetMouseCapturer(),
-                 "Capturing frame should have a mouse capturer" );
-
-    NS_ASSERTION(!capturingFrame || mPresContext == capturingFrame->PresContext(),
-                 "Shouldn't have different pres contexts");
-
-    NS_ASSERTION(capturingFrame != mPresContext->PresShell()->FrameManager()->GetRootFrame(),
-                 "Capturing frame should not be the root frame");
-
-    if (capturingFrame)
-    {
-      mContent = capturingFrame->GetContent();
-      NS_ASSERTION(mContent, "Need content");
-
-      NS_ASSERTION(mContent != mPresContext->PresShell()->FrameManager()->GetRootFrame()->GetContent(),
-                 "We didn't want the root content!");
-
-      NS_ASSERTION(capturingFrame == nsFrame::GetNearestCapturingFrame(
-                   mPresContext->PresShell()->GetPrimaryFrameFor(mContent)),
-                   "Mapping of frame to content failed.");
-    }
-
-    // Check that if there was no capturing frame the content is null.
-    NS_ASSERTION(capturingFrame || !mContent, "Content not cleared correctly.");
+    mContent = nsIPresShell::GetCapturingContent();
 
     if (!mTimer)
     {
       nsresult result;
       mTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
 
       if (NS_FAILED(result))
         return result;
@@ -489,56 +460,24 @@ public:
     mDelay = aDelay;
     return NS_OK;
   }
 
   NS_IMETHOD Notify(nsITimer *timer)
   {
     if (mSelection && mPresContext)
     {
-      // If the content is null the capturing frame must be the root frame.
-      nsIFrame* capturingFrame;
-      if (mContent)
-      {
-        nsIFrame* contentFrame = mPresContext->PresShell()->GetPrimaryFrameFor(mContent);
-        if (contentFrame)
-        {
-          capturingFrame = nsFrame::GetNearestCapturingFrame(contentFrame);
-        }
-        else 
-        {
-          capturingFrame = nsnull;
-        }
-        NS_ASSERTION(!capturingFrame || capturingFrame->GetMouseCapturer(),
-                     "Capturing frame should have a mouse capturer" );
-      }
-      else
-      {
-        capturingFrame = mPresContext->PresShell()->FrameManager()->GetRootFrame();
-      }
-
-      // Clear the content reference now that the frame has been found.
+      nsWeakFrame frame = mPresContext->PresShell()->GetPrimaryFrameFor(mContent);
       mContent = nsnull;
 
-      // This could happen for a frame with style changed to display:none or a frame
-      // that was destroyed.
-      if (!capturingFrame) {
-        NS_WARNING("Frame destroyed or set to display:none before scroll timer fired.");
-        return NS_OK;
-      }
-
-      nsIView* captureView = capturingFrame->GetMouseCapturer();
-    
-      nsWeakFrame viewFrame = static_cast<nsIFrame*>(captureView->GetClientData());
-      NS_ASSERTION(viewFrame.GetFrame(), "View must have a client frame");
-      
-      mFrameSelection->HandleDrag(viewFrame, mPoint);
-
+      mFrameSelection->HandleDrag(frame, mPoint);
+
+      nsPoint pnt;
       mSelection->DoAutoScrollView(mPresContext,
-                                   viewFrame.IsAlive() ? captureView : nsnull,
+                                   frame.IsAlive() ? frame->GetClosestView(&pnt) : nsnull,
                                    mPoint, PR_TRUE);
     }
     return NS_OK;
   }
 private:
   nsFrameSelection *mFrameSelection;
   nsTypedSelection *mSelection;
   nsPresContext *mPresContext;
@@ -5000,17 +4939,17 @@ nsTypedSelection::DoAutoScrollView(nsPre
     // Map the globalPoint back into aView's coordinate system. We
     // have to get the globalOffsets again because aView's
     // window and its parents may have changed their offsets.
     //
     result = GetViewAncestorOffset(aView, nsnull, &globalOffset.x, &globalOffset.y);
     NS_ENSURE_SUCCESS(result, result);
 
     nsPoint svPoint = globalPoint - globalOffset;
-    mAutoScrollTimer->Start(aPresContext, aView, svPoint);
+    mAutoScrollTimer->Start(aPresContext, svPoint);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTypedSelection::GetEnumerator(nsIEnumerator **aIterator)
 {
--- a/layout/generic/test/test_bug470212.html
+++ b/layout/generic/test/test_bug470212.html
@@ -23,16 +23,17 @@ function doShiftDrag(){
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     var wu =  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                     .getInterface(Components.interfaces.nsIDOMWindowUtils);
     wu.sendMouseEvent('mousedown',  0, 50, 0, 1, 4);
     wu.sendMouseEvent('mousemove',  70, 70, 0, 0, 4);
     wu.sendMouseEvent('mousemove',  80, 500, 0, 0, 4);
 
     is(window.getSelection().rangeCount, 0, "rangeCount should be 0");
+    wu.sendMouseEvent('mouseup',  80, 500, 0, 0, 4);
 
     SimpleTest.finish();
   }, 0);
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(doShiftDrag);
 </script>
--- a/layout/xul/base/src/nsResizerFrame.cpp
+++ b/layout/xul/base/src/nsResizerFrame.cpp
@@ -106,18 +106,17 @@ nsResizerFrame::HandleEvent(nsPresContex
          if (rv == NS_ERROR_NOT_IMPLEMENTED) {
            // there's no native resize support, 
            // we need to window resizing ourselves
 
            // we're tracking.
            mTrackingMouseMove = PR_TRUE;
 
            // start capture.
-           aEvent->widget->CaptureMouse(PR_TRUE);
-           CaptureMouseEvents(aPresContext,PR_TRUE);
+           nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
 
            // remember current mouse coordinates.
            mLastPoint = aEvent->refPoint;
            aEvent->widget->GetScreenBounds(mWidgetRect);
          }
 
          *aEventStatus = nsEventStatus_eConsumeNoDefault;
          doDefault = PR_FALSE;
@@ -131,18 +130,17 @@ nsResizerFrame::HandleEvent(nsPresContex
        if(mTrackingMouseMove && aEvent->eventStructType == NS_MOUSE_EVENT &&
           static_cast<nsMouseEvent*>(aEvent)->button ==
             nsMouseEvent::eLeftButton)
        {
          // we're done tracking.
          mTrackingMouseMove = PR_FALSE;
 
          // end capture
-         aEvent->widget->CaptureMouse(PR_FALSE);
-         CaptureMouseEvents(aPresContext,PR_FALSE);
+         nsIPresShell::SetCapturingContent(nsnull, 0);
 
          *aEventStatus = nsEventStatus_eConsumeNoDefault;
          doDefault = PR_FALSE;
        }
      }
      break;
 
    case NS_MOUSE_MOVE: {
--- a/layout/xul/base/src/nsSliderFrame.cpp
+++ b/layout/xul/base/src/nsSliderFrame.cpp
@@ -50,17 +50,16 @@
 #include "nsIContent.h"
 #include "nsCOMPtr.h"
 #include "nsINameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLParts.h"
 #include "nsIPresShell.h"
 #include "nsCSSRendering.h"
 #include "nsIDOMEventTarget.h"
-#include "nsIViewManager.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDocument.h"
 #include "nsScrollbarButtonFrame.h"
 #include "nsISliderListener.h"
 #include "nsIScrollbarMediator.h"
 #include "nsIScrollbarFrame.h"
 #include "nsILookAndFeel.h"
 #include "nsRepeatService.h"
@@ -119,17 +118,16 @@ nsSliderFrame::Init(nsIContent*      aCo
     gotPrefs = PR_TRUE;
 
     gMiddlePref = nsContentUtils::GetBoolPref("middlemouse.scrollbarPosition");
     gSnapMultiplier = nsContentUtils::GetIntPref("slider.snapMultiplier");
   }
 
   mCurPos = GetCurrentPosition(aContent);
 
-  CreateViewForFrame(PresContext(), this, GetStyleContext(), PR_TRUE);
   return rv;
 }
 
 NS_IMETHODIMP
 nsSliderFrame::RemoveFrame(nsIAtom*        aListName,
                            nsIFrame*       aOldFrame)
 {
   nsresult rv = nsBoxFrame::RemoveFrame(aListName, aOldFrame);
@@ -974,52 +972,24 @@ nsSliderFrame::DragThumb(PRBool aGrabMou
   if (parent) {
     nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
     if (sliderListener) {
       nsContentUtils::AddScriptRunner(
         new nsDragStateChangedRunnable(sliderListener, aGrabMouseEvents));
     }
   }
 
-  // get its view
-  nsIView* view = GetView();
-
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-
-    if (viewMan) {
-      PRBool result;
-
-      if (aGrabMouseEvents) {
-        viewMan->GrabMouseEvents(view,result);
-      } else {
-        viewMan->GrabMouseEvents(nsnull,result);
-      }
-    }
-  }
+  nsIPresShell::SetCapturingContent(aGrabMouseEvents ? GetContent() : nsnull,
+                                    aGrabMouseEvents ? CAPTURE_IGNOREALLOWED : 0);
 }
 
 PRBool
 nsSliderFrame::isDraggingThumb()
 {
-  // get its view
-  nsIView* view = GetView();
-
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-
-    if (viewMan) {
-        nsIView* grabbingView;
-        viewMan->GetMouseEventGrabber(grabbingView);
-        if (grabbingView == view)
-          return PR_TRUE;
-    }
-  }
-
-  return PR_FALSE;
+  return (nsIPresShell::GetCapturingContent() == GetContent());
 }
 
 void
 nsSliderFrame::AddListener()
 {
   if (!mMediator) {
     mMediator = new nsSliderMediator(this);
   }
--- a/layout/xul/base/src/nsSliderFrame.h
+++ b/layout/xul/base/src/nsSliderFrame.h
@@ -181,18 +181,16 @@ public:
   static PRInt32 GetCurrentPosition(nsIContent* content);
   static PRInt32 GetMinPosition(nsIContent* content);
   static PRInt32 GetMaxPosition(nsIContent* content);
   static PRInt32 GetIncrement(nsIContent* content);
   static PRInt32 GetPageIncrement(nsIContent* content);
   static PRInt32 GetIntegerAttribute(nsIContent* content, nsIAtom* atom, PRInt32 defaultValue);
   void EnsureOrient();
 
-  virtual nsIView* GetMouseCapturer() const { return GetView(); }
-
   NS_IMETHOD HandlePress(nsPresContext* aPresContext,
                          nsGUIEvent *    aEvent,
                          nsEventStatus*  aEventStatus);
 
   NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
                                  nsGUIEvent *    aEvent,
                                  nsEventStatus*  aEventStatus,
                                  PRBool aControlHeld)  { return NS_OK; }
--- a/layout/xul/base/src/nsSplitterFrame.cpp
+++ b/layout/xul/base/src/nsSplitterFrame.cpp
@@ -50,19 +50,16 @@
 #include "nsIDOMDocument.h"
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsINameSpaceManager.h"
 #include "nsScrollbarButtonFrame.h"
 #include "nsIDOMMouseListener.h"
 #include "nsIDOMMouseMotionListener.h"
 #include "nsIDOMEventTarget.h"
-#include "nsIView.h"
-#include "nsIViewManager.h"
-#include "nsIScrollableView.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIPresShell.h"
 #include "nsFrameList.h"
 #include "nsHTMLParts.h"
 #include "nsILookAndFeel.h"
 #include "nsStyleContext.h"
 #include "nsBoxLayoutState.h"
 #include "nsIXBLService.h"
@@ -142,18 +139,16 @@ public:
   enum ResizeType { Closest, Farthest, Flex, Grow };
   enum State { Open, CollapsedBefore, CollapsedAfter, Dragging };
   enum CollapseDirection { Before, After };
 
   ResizeType GetResizeBefore();
   ResizeType GetResizeAfter();
   State GetState();
 
-  //nsresult CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents);
-  //PRBool IsMouseCaptured(nsPresContext* aPresContext);
   void Reverse(nsSplitterInfo*& aIndexes, PRInt32 aCount);
   PRBool SupportsCollapseDirection(CollapseDirection aDirection);
 
   void EnsureOrient();
   void SetPreferredSize(nsBoxLayoutState& aState, nsIBox* aChildBox, nscoord aOnePixel, PRBool aIsHorizontal, nscoord* aSize);
 
   nsSplitterFrame* mOuter;
   PRBool mDidDrag;
@@ -162,17 +157,16 @@ public:
   nsIBox* mParentBox;
   PRBool mPressed;
   nsSplitterInfo* mChildInfosBefore;
   nsSplitterInfo* mChildInfosAfter;
   PRInt32 mChildInfosBeforeCount;
   PRInt32 mChildInfosAfterCount;
   State mState;
   nscoord mSplitterPos;
-  nscoord mSplitterViewPos;
   PRBool mDragging;
 
 };
 
 
 NS_IMPL_ADDREF(nsSplitterFrameInner)
 NS_IMPL_RELEASE(nsSplitterFrameInner)
 NS_INTERFACE_MAP_BEGIN(nsSplitterFrameInner)
@@ -348,19 +342,16 @@ nsSplitterFrame::Init(nsIContent*      a
         SetStyleContextWithoutNotification(newContext);
       }
     }
   }
 
   nsresult  rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   mInner->mState = nsSplitterFrameInner::Open;
   mInner->AddListener(PresContext());
   mInner->mParentBox = nsnull;
   return rv;
 }
 
 NS_IMETHODIMP
 nsSplitterFrame::DoLayout(nsBoxLayoutState& aState)
@@ -469,17 +460,17 @@ nsSplitterFrame::HandleEvent(nsPresConte
 }
 
 void
 nsSplitterFrameInner::MouseUp(nsPresContext* aPresContext, nsGUIEvent* aEvent)
 {
   if (mDragging && mOuter) {
     AdjustChildren(aPresContext);
     AddListener(aPresContext);
-    mOuter->CaptureMouse(aPresContext, PR_FALSE);
+    nsIPresShell::SetCapturingContent(nsnull, 0); // XXXndeakin is this needed?
     mDragging = PR_FALSE;
     State newState = GetState(); 
     // if the state is dragging then make it Open.
     if (newState == Dragging)
       mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, EmptyString(), PR_TRUE);
 
     mPressed = PR_FALSE;
 
@@ -583,30 +574,16 @@ nsSplitterFrameInner::MouseDrag(nsPresCo
     } else {
       // if we are not in a collapsed position and we are not dragging make sure
       // we are dragging.
       if (currentState != Dragging)
         mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("dragging"), PR_TRUE);
       AdjustChildren(aPresContext);
     }
 
-    // printf("----- resize ----- ");
-    /*
-      for (i=0; i < mChildInfosBeforeCount; i++) 
-        printf("before, index=%d, current=%d, changed=%d\n", mChildInfosBefore[i].index, mChildInfosBefore[i].current, mChildInfosBefore[i].changed);
-      for (i=0; i < mChildInfosAfterCount; i++) 
-        printf("after, index=%d, current=%d, changed=%d\n", mChildInfosAfter[i].index, mChildInfosAfter[i].current, mChildInfosAfter[i].changed);
-    */
-
-    /*
-      nsIPresShell *shell = aPresContext->PresShell();
-
-      shell->FrameNeedsReflow(mOuter, nsIPresShell::eStyleChange,
-                              NS_FRAME_IS_DIRTY);
-    */
     mDidDrag = PR_TRUE;
   }
 }
 
 void
 nsSplitterFrameInner::AddListener(nsPresContext* aPresContext)
 {
   mOuter->GetContent()->
@@ -624,72 +601,23 @@ nsSplitterFrameInner::RemoveListener()
   mOuter->GetContent()->
     RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
                              NS_GET_IID(nsIDOMMouseListener));
   mOuter->GetContent()->
     RemoveEventListenerByIID(static_cast<nsIDOMMouseMotionListener*>(this),
                              NS_GET_IID(nsIDOMMouseMotionListener));
 }
 
-/*
-nsresult
-nsSplitterFrameInner :: CaptureMouse(nsPresContext* aPresContext, PRBool aGrabMouseEvents)
-{
-  // get its view
-  nsIView* view = mOuter->GetView();
-  PRBool result;
-
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-    if (viewMan) {
-      // nsIWidget* widget = view->GetWidget();
-      if (aGrabMouseEvents) {
-        viewMan->GrabMouseEvents(view,result);
-        //  if (widget)
-        //   widget->CaptureMouse(PR_TRUE);
-      } else {
-        viewMan->GrabMouseEvents(nsnull,result);
-       // if (widget)
-         //  widget->CaptureMouse(PR_FALSE);
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-
-PRBool
-nsSplitterFrameInner :: IsMouseCaptured(nsPresContext* aPresContext)
-{
-    // get its view
-  nsIView* view = mOuter->GetView();
-  
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-
-    if (viewMan) {
-        nsIView* grabbingView;
-        viewMan->GetMouseEventGrabber(grabbingView);
-        if (grabbingView == view)
-          return PR_TRUE;
-    }
-  }
-
-  return PR_FALSE;
-}
-*/
-
 nsresult
 nsSplitterFrameInner::MouseUp(nsIDOMEvent* aMouseEvent)
 {  
   NS_ENSURE_TRUE(mOuter, NS_OK);
   mPressed = PR_FALSE;
 
-  mOuter->CaptureMouse(mOuter->PresContext(), PR_FALSE);
+  nsIPresShell::SetCapturingContent(nsnull, 0);
 
   return NS_OK;
 }
 
 nsresult
 nsSplitterFrameInner::MouseDown(nsIDOMEvent* aMouseEvent)
 {  
   NS_ENSURE_TRUE(mOuter, NS_OK);
@@ -840,36 +768,32 @@ nsSplitterFrameInner::MouseDown(nsIDOMEv
   if (resizeAfter == Farthest)
      Reverse(mChildInfosAfter, mChildInfosAfterCount);
 
   // grow only applys to the children after. If grow is set then no space should be taken out of any children after
   // us. To do this we just set the size of that list to be 0.
   if (resizeAfter == Grow)
      mChildInfosAfterCount = 0;
 
-  nsRect vr = mOuter->GetView()->GetBounds();
-
   PRInt32 c;
   nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(mouseEvent,
                                                                mParentBox);
   if (isHorizontal) {
      c = pt.x;
      mSplitterPos = mOuter->mRect.x;
-     mSplitterViewPos = vr.x;
   } else {
      c = pt.y;
      mSplitterPos = mOuter->mRect.y;
-     mSplitterViewPos = vr.y;
   }
 
   mDragStart = c;
 
   //printf("Pressed mDragStart=%d\n",mDragStart);
 
-  mOuter->CaptureMouse(outerPresContext, PR_TRUE);
+  nsIPresShell::SetCapturingContent(mOuter->GetContent(), CAPTURE_IGNOREALLOWED);
 
   return NS_OK;
 }
 
 nsresult
 nsSplitterFrameInner::MouseMove(nsIDOMEvent* aMouseEvent)
 {  
   NS_ENSURE_TRUE(mOuter, NS_OK);
--- a/layout/xul/base/src/nsSplitterFrame.h
+++ b/layout/xul/base/src/nsSplitterFrame.h
@@ -99,18 +99,16 @@ public:
                          nsEventStatus* aEventStatus);
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   virtual void GetInitialOrientation(PRBool& aIsHorizontal); 
 
-  virtual nsIView* GetMouseCapturer() const { return GetView(); }
-
 private:
 
   friend class nsSplitterFrameInner;
   nsSplitterFrameInner* mInner;
 
 }; // class nsSplitterFrame
 
 #endif
--- a/layout/xul/base/src/nsTitleBarFrame.cpp
+++ b/layout/xul/base/src/nsTitleBarFrame.cpp
@@ -43,17 +43,16 @@
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMNodeList.h"
 #include "nsGkAtoms.h"
 #include "nsIWidget.h"
 #include "nsMenuPopupFrame.h"
 #include "nsPresContext.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsPIDOMWindow.h"
-#include "nsIViewManager.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsDisplayList.h"
 #include "nsContentUtils.h"
 
 //
 // NS_NewTitleBarFrame
 //
@@ -68,30 +67,16 @@ NS_NewTitleBarFrame(nsIPresShell* aPresS
 NS_IMPL_FRAMEARENA_HELPERS(nsTitleBarFrame)
 
 nsTitleBarFrame::nsTitleBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 :nsBoxFrame(aPresShell, aContext, PR_FALSE)
 {
   mTrackingMouseMove = PR_FALSE;
 }
 
-
-
-NS_IMETHODIMP
-nsTitleBarFrame::Init(nsIContent*      aContent,
-                      nsIFrame*        aParent,
-                      nsIFrame*        asPrevInFlow)
-{
-  nsresult rv = nsBoxFrame::Init(aContent, aParent, asPrevInFlow);
-
-  CreateViewForFrame(PresContext(), this, GetStyleContext(), PR_TRUE);
-
-  return rv;
-}
-
 NS_IMETHODIMP
 nsTitleBarFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                              const nsRect&           aDirtyRect,
                                              const nsDisplayListSet& aLists)
 {
   // override, since we don't want children to get events
   if (aBuilder->IsForEventDelivery()) {
     if (!mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowevents,
@@ -126,17 +111,17 @@ nsTitleBarFrame::HandleEvent(nsPresConte
          if (dsti) {
            PRInt32 type = -1;
            if (NS_SUCCEEDED(dsti->GetItemType(&type)) &&
                type == nsIDocShellTreeItem::typeChrome) {
              // we're tracking.
              mTrackingMouseMove = PR_TRUE;
 
              // start capture.
-             CaptureMouseEvents(aPresContext,PR_TRUE);
+             nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
 
              // remember current mouse coordinates.
              mLastPoint = aEvent->refPoint;
            }
          }
 
          *aEventStatus = nsEventStatus_eConsumeNoDefault;
          doDefault = PR_FALSE;
@@ -149,17 +134,17 @@ nsTitleBarFrame::HandleEvent(nsPresConte
        if(mTrackingMouseMove && aEvent->eventStructType == NS_MOUSE_EVENT &&
           static_cast<nsMouseEvent*>(aEvent)->button ==
             nsMouseEvent::eLeftButton)
        {
          // we're done tracking.
          mTrackingMouseMove = PR_FALSE;
 
          // end capture
-         CaptureMouseEvents(aPresContext,PR_FALSE);
+         nsIPresShell::SetCapturingContent(nsnull, 0);
 
          *aEventStatus = nsEventStatus_eConsumeNoDefault;
          doDefault = PR_FALSE;
        }
      }
      break;
 
    case NS_MOUSE_MOVE: {
@@ -207,45 +192,16 @@ nsTitleBarFrame::HandleEvent(nsPresConte
   }
 
   if ( doDefault )
     return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
   else
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsTitleBarFrame::CaptureMouseEvents(nsPresContext* aPresContext,PRBool aGrabMouseEvents)
-{
-  // get its view
-  nsIView* view = GetView();
-  PRBool result;
-
-  if (view) {
-    nsIViewManager* viewMan = view->GetViewManager();
-    if (viewMan) {
-      // nsIWidget* widget = view->GetWidget();
-      if (aGrabMouseEvents) {
-        viewMan->GrabMouseEvents(view,result);
-        //mIsCapturingMouseEvents = PR_TRUE;
-        //widget->CaptureMouse(PR_TRUE);
-      } else {
-        viewMan->GrabMouseEvents(nsnull,result);
-        //mIsCapturingMouseEvents = PR_FALSE;
-        //widget->CaptureMouse(PR_FALSE);
-      }
-    }
-  }
-
-  return NS_OK;
-
-}
-
-
-
 void
 nsTitleBarFrame::MouseClicked(nsPresContext* aPresContext, nsGUIEvent* aEvent)
 {
   // Execute the oncommand event handler.
   nsContentUtils::DispatchXULCommand(mContent,
                                      aEvent ?
                                        NS_IS_TRUSTED_EVENT(aEvent) : PR_FALSE);
 }
--- a/layout/xul/base/src/nsTitleBarFrame.h
+++ b/layout/xul/base/src/nsTitleBarFrame.h
@@ -44,36 +44,28 @@ class nsTitleBarFrame : public nsBoxFram
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewTitleBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);  
 
   nsTitleBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
-  NS_IMETHOD  Init(nsIContent*      aContent,
-                   nsIFrame*        aParent,
-                   nsIFrame*        asPrevInFlow);
-
   NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                          const nsRect&           aDirtyRect,
                                          const nsDisplayListSet& aLists);
 
   NS_IMETHOD HandleEvent(nsPresContext* aPresContext, 
                                       nsGUIEvent* aEvent,
                                       nsEventStatus* aEventStatus);
 
   virtual PRBool GetMouseThrough() const { return PR_FALSE; }
 
   virtual void MouseClicked(nsPresContext* aPresContext, nsGUIEvent* aEvent);
 
 protected:
-
-  NS_IMETHOD CaptureMouseEvents(nsPresContext* aPresContext,PRBool aGrabMouseEvents);
-
-protected:
 	PRBool mTrackingMouseMove;	
 	nsIntPoint mLastPoint;
 
 
 }; // class nsTitleBarFrame
 
 #endif /* nsTitleBarFrame_h___ */
--- a/layout/xul/base/src/nsXULPopupManager.cpp
+++ b/layout/xul/base/src/nsXULPopupManager.cpp
@@ -2096,17 +2096,17 @@ nsXULMenuCommandEvent::Run()
     nsPresContext* presContext = menuFrame->PresContext();
     nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
     nsCOMPtr<nsIViewManager> kungFuDeathGrip = shell->GetViewManager();
 
     // Deselect ourselves.
     if (mCloseMenuMode != CloseMenuMode_None)
       menuFrame->SelectMenu(PR_FALSE);
 
-    nsAutoHandlingUserInputStatePusher userInpStatePusher(mUserInput);
+    nsAutoHandlingUserInputStatePusher userInpStatePusher(mUserInput, PR_FALSE);
     nsContentUtils::DispatchXULCommand(mMenu, mIsTrusted, nsnull, shell,
                                        mControl, mAlt, mShift, mMeta);
   }
 
   if (popup && mCloseMenuMode != CloseMenuMode_None)
     pm->HidePopup(popup, mCloseMenuMode == CloseMenuMode_Auto, PR_TRUE, PR_FALSE);
 
   return NS_OK;
--- a/toolkit/content/tests/widgets/Makefile.in
+++ b/toolkit/content/tests/widgets/Makefile.in
@@ -98,16 +98,17 @@ include $(topsrcdir)/config/rules.mk
 		test_popuphidden.xul \
 		test_popup_scaled.xul \
 		test_popupremoving.xul \
 		test_popupremoving_frame.xul \
 		frame_popupremoving_frame.xul \
 		test_position.xul \
 		test_menu.xul \
 		test_menu_hide.xul \
+		test_mousecapture.xul \
 		test_focus.xul \
 		test_focus_anons.xul \
 		test_tabindex.xul \
 		test_mousescroll.xul \
 		test_scrollbar.xul \
 		test_sorttemplate.xul \
 		test_contextmenu_list.xul \
 		test_videocontrols.html \
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/widgets/test_mousecapture.xul
@@ -0,0 +1,191 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Mouse Capture Tests" align="start"
+        onload="setTimeout(runTests, 0);"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/javascript" src="/MochiKit/packed.js"></script>
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+
+<script>
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+var captureRetargetMode = false;
+var cachedMouseDown = null;
+var previousWidth = 0, originalWidth = 0;
+
+function splitterCallback(adjustment)
+{
+  var newWidth = Number($("leftbox").width); // getBoundingClientRect().width;
+  var expectedWidth = previousWidth + adjustment;
+  if (expectedWidth > $("splitterbox").getBoundingClientRect().width)
+    expectedWidth = $("splitterbox").getBoundingClientRect().width - $("splitter").getBoundingClientRect().width;
+  is(newWidth, expectedWidth, "splitter left box size (" + adjustment + ")");
+  previousWidth = newWidth;
+}
+
+function selectionCallback(adjustment)
+{
+  if (adjustment == 4000) {
+    is(frames[0].getSelection().toString(), "This is some text", "selection after drag (" + adjustment + ")");
+    ok(frames[0].scrollY > 40, "selection caused scroll down (" + adjustment + ")");
+  }
+  else {
+    if (adjustment == 0) {
+      is(frames[0].getSelection().toString(), ".", "selection after drag (" + adjustment + ")");
+    }
+    is(frames[0].scrollY, 0, "selection scrollY (" + adjustment + ")");
+  }
+}
+
+function framesetCallback(adjustment)
+{
+  var newWidth = frames[1].frames[0].document.documentElement.clientWidth;
+  var expectedWidth = originalWidth + adjustment;
+  if (adjustment == 0)
+    expectedWidth = originalWidth - 12;
+  else if (expectedWidth >= 4000)
+    expectedWidth = originalWidth * 2 - 2;
+
+  is(newWidth, expectedWidth, "frameset after drag (" + adjustment + ")");
+}
+
+function runTests()
+{
+  previousWidth = $("leftbox").getBoundingClientRect().width;
+  runCaptureTest($("splitter"), splitterCallback);
+
+  var custom = document.getElementById("custom");
+  runCaptureTest(custom);
+
+  synthesizeMouseExpectEvent($("rightbox"), 2, 2, { type: "mousemove" },
+                             $("rightbox"), "mousemove", "setCapture and releaseCapture");
+
+  custom.setCapture();
+  synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
+                             $("leftbox"), "mousemove", "setCapture fails on non mousedown");
+
+  var custom2 = document.getElementById("custom2");
+  synthesizeMouse(custom2, 2, 2, { type: "mousedown" });
+  synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
+                             $("leftbox"), "mousemove", "document.releaseCapture releases capture");
+
+  var custom3 = document.getElementById("custom3");
+  synthesizeMouse(custom3, 2, 2, { type: "mousedown" });
+  synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
+                             $("leftbox"), "mousemove", "element.releaseCapture releases capture");
+
+  var custom4 = document.getElementById("custom4");
+  synthesizeMouse(custom4, 2, 2, { type: "mousedown" });
+  synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
+                             custom4, "mousemove", "element.releaseCapture during mousemove before releaseCapture");
+  synthesizeMouseExpectEvent($("leftbox"), 2, 2, { type: "mousemove" },
+                             $("leftbox"), "mousemove", "element.releaseCapture during mousemove after releaseCapture");
+
+  var custom5 = document.getElementById("custom5");
+  runCaptureTest(custom5);
+  captureRetargetMode = true;
+  runCaptureTest(custom5);
+  captureRetargetMode = false;
+
+  var b = frames[0].document.getElementById("b");
+  runCaptureTest(b, selectionCallback);
+
+  previousWidth = frames[1].frames[0].document.documentElement.clientWidth;
+  originalWidth = previousWidth;
+  runCaptureTest(frames[1].document.documentElement.lastChild, framesetCallback);
+
+  SimpleTest.finish();
+}
+
+function runCaptureTest(element, callback)
+{
+  var expectedTarget = null;
+
+  var win = element.ownerDocument.defaultView;
+
+  function mouseMoved(event) {
+    is(event.originalTarget, expectedTarget,
+       expectedTarget.id + " target for point " + event.clientX + "," + event.clientY);
+  }
+  win.addEventListener("mousemove", mouseMoved, false);
+
+  expectedTarget = element;
+
+  var basepoint = element.localName == "frameset" ? 50 : 2;
+  synthesizeMouse(element, basepoint, basepoint, { type: "mousedown" }, win);
+
+  // in setCapture(true) mode, all events should fire on custom5. In
+  // setCapture(false) mode, events can fire at a descendant
+  if (expectedTarget == $("custom5") && !captureRetargetMode)
+    expectedTarget = $("custom5spacer");
+
+  // releaseCapture should do nothing for an element which isn't capturing
+  $("splitterbox").releaseCapture();
+
+  synthesizeMouse(element, basepoint + 2, basepoint + 2, { type: "mousemove" }, win);
+  if (callback)
+    callback(2);
+
+  if (expectedTarget == $("custom5spacer") && !captureRetargetMode)
+    expectedTarget = $("custom5inner");
+
+  synthesizeMouse(element, basepoint + 25, basepoint + 25, { type: "mousemove" }, win);
+  if (callback)
+    callback(25);
+
+  expectedTarget = element.localName == "b" ? win.document.documentElement : element;
+  synthesizeMouse(element, basepoint + 4000, basepoint + 4000, { type: "mousemove" }, win);
+  if (callback)
+    callback(4000);
+  synthesizeMouse(element, basepoint - 12, basepoint - 12, { type: "mousemove" }, win);
+  if (callback)
+    callback(-12);
+
+  expectedTarget = element.localName == "frameset" ? element : win.document.documentElement;
+  synthesizeMouse(element, basepoint + 30, basepoint + 30, { type: "mouseup" }, win);
+  synthesizeMouse(win.document.documentElement, 2, 2, { type: "mousemove" }, win);
+  if (callback)
+    callback(0);
+
+  win.removeEventListener("mousemove", mouseMoved, false);
+}
+
+]]>
+</script>
+
+<hbox id="splitterbox" style="margin-top: 5px;" onmousedown="this.setCapture()">
+  <hbox id="leftbox" width="100" flex="1"/>
+  <splitter id="splitter" height="5"/>
+  <hbox id="rightbox" width="100" flex="1"/>
+</hbox>
+
+<vbox id="custom" width="10" height="10" onmousedown="this.setCapture(); cachedMouseDown = event;"/>
+<vbox id="custom2" width="10" height="10" onmousedown="this.setCapture(); document.releaseCapture();"/>
+<vbox id="custom3" width="10" height="10" onmousedown="this.setCapture(); this.releaseCapture();"/>
+<vbox id="custom4" width="10" height="10" onmousedown="this.setCapture();"
+                                          onmousemove="this.releaseCapture();"/>
+<hbox id="custom5" width="40" height="40"
+      onmousedown="this.setCapture(captureRetargetMode);">
+  <spacer id="custom5spacer" width="5"/>
+  <hbox id="custom5inner" width="35" height="35"/>
+</hbox>
+
+<hbox>
+  <iframe width="100" height="100"
+          src="data:text/html,%3Cbody style%3D'font-size%3A 40pt%3B'%3E.%3Cb id%3D'b'%3EThis%3C/b%3E is some text%3C/body%3E"/>
+
+  <iframe width="100" height="100"
+          src="data:text/html,%3Cframeset cols='50%, 50%'%3E%3Cframe src='about:blank'%3E%3Cframe src='about:blank'%3E%3C/frameset%3E"/>
+</hbox>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+  <p id="display"/><div id="content" style="display: none"/><pre id="test"/>
+</body>
+
+</window>
--- a/toolkit/content/tests/widgets/test_scale.xul
+++ b/toolkit/content/tests/widgets/test_scale.xul
@@ -207,16 +207,40 @@ function testtag_scale_UI_Mouse(element,
 
   var rect = element.getBoundingClientRect();
   synthesizeMouseExpectEvent(element, rect.right - rect.left - hmove,
                              rect.bottom - rect.top - vmove, { },
                              element, "change", testid + " mouse on right movetoclick=false");
   is(element.value, endval, testid + " mouse on right movetoclick=false");
 
   element.removeAttribute("movetoclick");
+
+  element.value = reverse ? element.max : element.min;
+
+  synthesizeMouse(element, 8, 8, { type: "mousedown" });
+  synthesizeMouse(element, horiz ? 2000 : 8, horiz ? 8 : 2000, { type: "mousemove" });
+  is(element.value, reverse ? element.min : element.max, testid + " move mouse too far after end");
+  synthesizeMouse(element, 2, 2, { type: "mouseup" });
+
+  synthesizeMouse(element, rect.width - 8, rect.height - 8, { type: "mousedown" });
+  synthesizeMouse(element, horiz ? -2000 : rect.width - 8, horiz ? rect.height - 8 : -2000, { type: "mousemove" });
+  is(element.value, reverse ? element.max : element.min, testid + " move mouse too far before start");
+
+  synthesizeMouse(element, 2, 2, { type: "mouseup" });
+
+  // now check if moving outside in both directions works. On Windows,
+  // it should snap back to the original location.
+  element.value = reverse ? element.max : element.min;
+
+  var expected = (navigator.platform.indexOf("Win") >= 0) ? element.value :
+                  (reverse ? element.min : element.max);
+  synthesizeMouse(element, 7, 7, { type: "mousedown" });
+  synthesizeMouse(element, 2000, 2000, { type: "mousemove" });
+  is(element.value, expected, testid + " move mouse ouside in both directions");
+  synthesizeMouse(element, 2, 2, { type: "mouseup" });
 }
 
 function testtag_scale_States(element, evalue, evalueattr, emin, emax, testid)
 {
   is(element.getAttribute("value"), evalueattr, testid + " value attribute");
   is(element.value, evalue, testid + " value");
   is(element.min, emin, testid + " min");
   is(element.max, emax, testid + " max");
--- a/view/public/nsIViewManager.h
+++ b/view/public/nsIViewManager.h
@@ -55,18 +55,18 @@ enum nsRectVisibility {
   nsRectVisibility_kAboveViewport, 
   nsRectVisibility_kBelowViewport, 
   nsRectVisibility_kLeftOfViewport, 
   nsRectVisibility_kRightOfViewport, 
   nsRectVisibility_kZeroAreaRect
 }; 
 
 #define NS_IVIEWMANAGER_IID   \
-  { 0x739bbc2b, 0x5c45, 0x40bb, \
-    { 0xb0, 0xbc, 0xe3, 0x1c, 0xe0, 0xf2, 0x19, 0xc2 } }
+  { 0xe1f3095c, 0x65cd, 0x46e1, \
+    { 0x9d, 0x70, 0x88, 0xcf, 0x54, 0x19, 0x9d, 0x05 } }
 
 class nsIViewManager : public nsISupports
 {
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWMANAGER_IID)
   /**
    * Initialize the ViewManager
@@ -183,31 +183,16 @@ public:
    * @param aEvent event to dispatch
    * @param aViewTarget dispatch the event to this view
    * @param aStatus event handling status
    */
   NS_IMETHOD  DispatchEvent(nsGUIEvent *aEvent,
       nsIView* aViewTarget, nsEventStatus* aStatus) = 0;
 
   /**
-   * Used to grab/capture all mouse events for a specific view,
-   * irrespective of the cursor position at which the
-   * event occurred.
-   * @param aView view to capture mouse events
-   * @result event handling status
-   */
-  NS_IMETHOD  GrabMouseEvents(nsIView *aView, PRBool& aResult) = 0;
-
-  /**
-   * Get the current view, if any, that's capturing mouse events.
-   * @result view that is capturing mouse events or nsnull
-   */
-  NS_IMETHOD  GetMouseEventGrabber(nsIView *&aView) = 0;
-
-  /**
    * Given a parent view, insert another view as its child.
    * aSibling and aAbove control the "document order" for the insertion.
    * If aSibling is null, the view is inserted at the end of the document order
    * if aAfter is PR_TRUE, otherwise it is inserted at the beginning.
    * If aSibling is non-null, then if aAfter is PR_TRUE, the view is inserted
    * after the sibling in document order (appearing above the sibling unless
    * overriden by z-order).
    * If it is PR_FALSE, the view is inserted before the sibling.
--- a/view/public/nsIViewObserver.h
+++ b/view/public/nsIViewObserver.h
@@ -41,20 +41,20 @@
 #include "nsISupports.h"
 #include "nsEvent.h"
 #include "nsColor.h"
 #include "nsRect.h"
 
 class nsIRenderingContext;
 class nsGUIEvent;
 
-// 52b3b616-23a9-4516-a8d3-452b4126eb2b
+// 8D7AE493-1EB1-4D38-89DA-9EEEAA29FD79
 #define NS_IVIEWOBSERVER_IID  \
-{ 0x52b3b616, 0x23a9, 0x4516, \
-  { 0xa8, 0xd3, 0x45, 0x2b, 0x41, 0x26, 0xeb, 0x2b } }
+{ 0x8d7ae493, 0x1eb1, 0x4d38, \
+  { 0x89, 0xda, 0x9e, 0xee, 0xaa, 0x29, 0xfd, 0x79 } }
 
 class nsIViewObserver : public nsISupports
 {
 public:
   
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWOBSERVER_IID)
 
   /* called when the observer needs to paint. This paints the entire
@@ -145,13 +145,20 @@ public:
 
   /**
    * Dispatch the given synthesized mouse move event, and if
    * aFlushOnHoverChange is true, flush layout if :hover changes cause
    * any restyles.
    */
   NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                            PRBool aFlushOnHoverChange) = 0;
+
+  /**
+   * If something within aView is capturing the mouse, clear the capture.
+   * if aView is null, clear the mouse capture no matter what is capturing it.
+   */
+  NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView) = 0;
+
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewObserver, NS_IVIEWOBSERVER_IID)
 
 #endif
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -180,23 +180,21 @@ nsView::nsView(nsViewManager* aViewManag
   // should make this promise explicitly by calling
   // SetViewContentTransparency.
   mVFlags = 0;
   mViewManager = aViewManager;
   mDirtyRegion = nsnull;
   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
-    mViewManager->GrabMouseEvents(GetParent(), boolResult);
+void nsView::DropMouseGrabbing()
+{
+  nsCOMPtr<nsIViewObserver> viewObserver = mViewManager->GetViewObserver();
+  if (viewObserver) {
+    viewObserver->ClearMouseCapture(this);
   }
 }
 
 nsView::~nsView()
 {
   MOZ_COUNT_DTOR(nsView);
 
   while (GetFirstChild())
@@ -490,25 +488,16 @@ NS_IMETHODIMP nsView::SetFloating(PRBool
 	}
 #endif
 
 	return NS_OK;
 }
 
 void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent)
 {
-  if (aViewManagerParent) {
-    // We're removed from the view hierarchy of aRemovalPoint, so make sure
-    // we're not still grabbing mouse events.
-    if (aViewManagerParent->GetMouseEventGrabber() == this) {
-      PRBool res;
-      aViewManagerParent->GrabMouseEvents(nsnull, res);
-    }
-  }
-
   if (mViewManager->GetRootView() == this)
     mViewManager->InvalidateHierarchy();
 
   for (nsView *child = mFirstChild; child; child = child->GetNextSibling())
     child->InvalidateHierarchy(aViewManagerParent);
 }
 
 void nsView::InsertChild(nsView *aChild, nsView *aSibling)
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -258,18 +258,16 @@ NS_IMETHODIMP nsViewManager::Init(nsIDev
   }
   if (nsnull != mContext) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
   mContext = aContext;
 
   mRefreshEnabled = PR_TRUE;
 
-  mMouseGrabber = nsnull;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP_(nsIView *)
 nsViewManager::CreateView(const nsRect& aBounds,
                           const nsIView* aParent,
                           nsViewVisibility aVisibilityFlag)
 {
@@ -1072,41 +1070,34 @@ NS_IMETHODIMP nsViewManager::DispatchEve
              aEvent->message != NS_MOUSE_ENTER) ||
             NS_IS_KEY_EVENT(aEvent) ||
             NS_IS_IME_EVENT(aEvent) ||
             NS_IS_PLUGIN_EVENT(aEvent)) {
           gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
         }
 
         if (aEvent->message == NS_DEACTIVATE) {
-          PRBool result;
-          GrabMouseEvents(nsnull, result);
+          // if a window is deactivated, clear the mouse capture regardless
+          // of what is capturing
+          nsIViewObserver* viewObserver = GetViewObserver();
+          if (viewObserver) {
+            viewObserver->ClearMouseCapture(nsnull);
+          }
         }
 
         //Find the view whose coordinates system we're in.
         nsView* baseView = static_cast<nsView*>(aView);
         nsView* view = baseView;
-        PRBool capturedEvent = PR_FALSE;
-        
+
         if (NS_IsEventUsingCoordinates(aEvent)) {
           // will dispatch using coordinates. Pretty bogus but it's consistent
           // with what presshell does.
           view = GetDisplayRootFor(baseView);
         }
 
-        //Find the view to which we're initially going to send the event 
-        //for hittesting.
-        if (NS_IS_MOUSE_EVENT(aEvent) || NS_IS_DRAG_EVENT(aEvent)) {
-          nsView* mouseGrabber = GetMouseEventGrabber();
-          if (mouseGrabber) {
-            view = mouseGrabber;
-            capturedEvent = PR_TRUE;
-          }
-        }
-
         if (nsnull != view) {
           PRInt32 p2a = mContext->AppUnitsPerDevPixel();
 
           if ((aEvent->message == NS_MOUSE_MOVE &&
                static_cast<nsMouseEvent*>(aEvent)->reason ==
                  nsMouseEvent::eReal) ||
               aEvent->message == NS_MOUSE_ENTER ||
               aEvent->message == NS_MOUSE_BUTTON_DOWN ||
@@ -1166,74 +1157,43 @@ NS_IMETHODIMP nsViewManager::DispatchEve
 
           nsPoint pt;
           pt.x = baseViewDimensions.x + 
             NSFloatPixelsToAppUnits(float(aEvent->refPoint.x) + 0.5f, p2a);
           pt.y = baseViewDimensions.y + 
             NSFloatPixelsToAppUnits(float(aEvent->refPoint.y) + 0.5f, p2a);
           pt += offset;
 
-          *aStatus = HandleEvent(view, pt, aEvent, capturedEvent);
+          *aStatus = HandleEvent(view, pt, aEvent);
         }
     
         break;
       }
     }
 
   return NS_OK;
 }
 
 nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsPoint aPoint,
-                                         nsGUIEvent* aEvent, PRBool aCaptured) {
+                                         nsGUIEvent* aEvent) {
 //printf(" %d %d %d %d (%d,%d) \n", this, event->widget, event->widgetSupports, 
 //       event->message, event->point.x, event->point.y);
 
   // Hold a refcount to the observer. The continued existence of the observer will
   // delay deletion of this view hierarchy should the event want to cause its
   // destruction in, say, some JavaScript event handler.
   nsCOMPtr<nsIViewObserver> obs = aView->GetViewManager()->GetViewObserver();
   nsEventStatus status = nsEventStatus_eIgnore;
   if (obs) {
      obs->HandleEvent(aView, aEvent, &status);
   }
 
   return status;
 }
 
-NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult)
-{
-  if (!IsRootVM()) {
-    return RootViewManager()->GrabMouseEvents(aView, aResult);
-  }
-
-  // Along with nsView::SetVisibility, we enforce that the mouse grabber
-  // can never be a hidden view.
-  if (aView && !static_cast<nsView*>(aView)->IsEffectivelyVisible()) {
-    aView = nsnull;
-  }
-
-#ifdef DEBUG_mjudge
-  if (aView)
-    {
-      printf("capturing mouse events for view %x\n",aView);
-    }
-  printf("removing mouse capture from view %x\n",mMouseGrabber);
-#endif
-
-  mMouseGrabber = static_cast<nsView*>(aView);
-  aResult = PR_TRUE;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView)
-{
-  aView = GetMouseEventGrabber();
-  return NS_OK;
-}
-
 // Recursively reparent widgets if necessary 
 
 void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)
 {
   if (aView->HasWidget()) {
     // Check to see if the parent widget is the
     // same as the new parent. If not then reparent
     // the widget, otherwise there is nothing more
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -123,20 +123,16 @@ public:
 
   NS_IMETHOD  UpdateView(nsIView *aView, PRUint32 aUpdateFlags);
   NS_IMETHOD  UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags);
   NS_IMETHOD  UpdateAllViews(PRUint32 aUpdateFlags);
 
   NS_IMETHOD  DispatchEvent(nsGUIEvent *aEvent,
       nsIView* aTargetView, nsEventStatus* aStatus);
 
-  NS_IMETHOD  GrabMouseEvents(nsIView *aView, PRBool &aResult);
-
-  NS_IMETHOD  GetMouseEventGrabber(nsIView *&aView);
-
   NS_IMETHOD  InsertChild(nsIView *parent, nsIView *child, nsIView *sibling,
                           PRBool above);
 
   NS_IMETHOD  InsertChild(nsIView *parent, nsIView *child,
                           PRInt32 zindex);
 
   NS_IMETHOD  RemoveChild(nsIView *parent);
 
@@ -300,24 +296,20 @@ private:
   }
 
   void SetPainting(PRBool aPainting) {
     RootViewManager()->mPainting = aPainting;
   }
 
 public: // NOT in nsIViewManager, so private to the view module
   nsView* GetRootView() const { return mRootView; }
-  nsView* GetMouseEventGrabber() const {
-    return RootViewManager()->mMouseGrabber;
-  }
   nsViewManager* RootViewManager() const { return mRootViewManager; }
   PRBool IsRootVM() const { return this == RootViewManager(); }
 
-  nsEventStatus HandleEvent(nsView* aView, nsPoint aPoint, nsGUIEvent* aEvent,
-                            PRBool aCaptured);
+  nsEventStatus HandleEvent(nsView* aView, nsPoint aPoint, nsGUIEvent* aEvent);
 
   /**
    * Called to inform the view manager that a view is about to bit-blit.
    * @param aView the view that will bit-blit
    * @param aScrollAmount how much aView will scroll by
    * @return always returns NS_OK
    * @note
    * This method used to return void, but MSVC 6.0 SP5 (without the
@@ -385,18 +377,16 @@ private:
 
   nsRevocableEventPtr<nsViewManagerEvent> mSynthMouseMoveEvent;
   nsRevocableEventPtr<nsViewManagerEvent> mInvalidateEvent;
 
   // The following members should not be accessed directly except by
   // the root view manager.  Some have accessor functions to enforce
   // this, as noted.
   
-  // Use GrabMouseEvents() and GetMouseEventGrabber() to access mMouseGrabber.
-  nsView            *mMouseGrabber;
   // Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(),
   // ClearUpdateCount() on the root viewmanager to access mUpdateCnt.
   PRInt32           mUpdateCnt;
   PRInt32           mUpdateBatchCnt;
   PRUint32          mUpdateBatchFlags;
   PRInt32           mScrollCnt;
   // Use IsRefreshEnabled() to check the value of mRefreshEnabled.
   PRPackedBool      mRefreshEnabled;
--- a/widget/src/xpwidgets/nsBaseDragService.cpp
+++ b/widget/src/xpwidgets/nsBaseDragService.cpp
@@ -222,30 +222,22 @@ nsBaseDragService::InvokeDragSession(nsI
   // stash the document of the dom node
   aDOMNode->GetOwnerDocument(getter_AddRefs(mSourceDocument));
   mSourceNode = aDOMNode;
   mEndDragPoint = nsIntPoint(0, 0);
 
   // When the mouse goes down, the selection code starts a mouse
   // capture. However, this gets in the way of determining drag
   // feedback for things like trees because the event coordinates
-  // are in the wrong coord system. Turn off mouse capture in
-  // the associated view manager.
-  nsCOMPtr<nsIContent> contentNode = do_QueryInterface(aDOMNode);
-  if (contentNode) {
-    nsIDocument* doc = contentNode->GetCurrentDoc();
-    if (doc) {
-      nsIPresShell* presShell = doc->GetPrimaryShell();
-      if (presShell) {
-        nsIViewManager* vm = presShell->GetViewManager();
-        if (vm) {
-          PRBool notUsed;
-          vm->GrabMouseEvents(nsnull, notUsed);
-        }
-      }
+  // are in the wrong coord system, so turn off mouse capture.
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
+  if (doc) {
+    nsCOMPtr<nsIViewObserver> viewObserver = do_QueryInterface(doc->GetPrimaryShell());
+    if (viewObserver) {
+      viewObserver->ClearMouseCapture(nsnull);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSessionWithImage(nsIDOMNode* aDOMNode,