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 idunknown
push userunknown
push dateunknown
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,