Bug 1428701- (Part 3) Allow a SelectRollupListener to handle the roll-up actions draft
authorEmma Malysz <emalysz@mozilla.com>
Mon, 25 Jun 2018 08:20:35 -0700
changeset 828268 37dd4782c4801e3fc4a9cceef3f6bcc4cf64a371
parent 809312 96399298b72f804bc5ce8d7dbf2039d108acd49b
push id118666
push userbmo:emalysz@mozilla.com
push dateFri, 10 Aug 2018 16:48:53 +0000
bugs1428701
milestone62.0a1
Bug 1428701- (Part 3) Allow a SelectRollupListener to handle the roll-up actions MozReview-Commit-ID: bZBac3lz84
dom/ipc/ContentParent.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
layout/forms/moz.build
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsListControlFrame.cpp
layout/generic/ViewportFrame.cpp
layout/generic/moz.build
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/generic/nsLineBox.h
widget/SelectRollupListener.cpp
widget/SelectRollupListener.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaUtils.h
widget/cocoa/nsCocoaUtils.mm
widget/gtk/nsWindow.cpp
widget/moz.build
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -136,16 +136,17 @@
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIParentChannel.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteWindowContext.h"
+#include "nsIRollupListener.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISiteSecurityService.h"
 #include "nsISound.h"
 #include "nsISpellChecker.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITimer.h"
 #include "nsIURIFixup.h"
@@ -167,16 +168,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsStyleSheetService.h"
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "PreallocatedProcessManager.h"
 #include "ProcessPriorityManager.h"
 #include "SandboxHal.h"
+#include "SelectRollupListener.h"
 #include "SourceSurfaceRawData.h"
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "nsDocShell.h"
 #include "nsOpenURIInFrameParams.h"
 #include "mozilla/net/NeckoMessageUtils.h"
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -159,16 +159,21 @@ parent:
 
     /**
      * When content moves focus from a native plugin window that's a child
      * of the native browser window we need to move native focus to the
      * browser. Otherwise the plugin window will never relinquish focus.
      */
     sync DispatchFocusToTopLevelWindow();
 
+    /**
+      * Checks for rollup commands
+    */
+    async CaptureRollupEvents(LayoutDeviceIntRect aRect, bool aDroppedDown);
+
 parent:
     /**
      * When child sends this message, parent should move focus to
      * the next or previous focusable element or document.
      */
     async MoveFocus(bool forward, bool forDocumentNavigation);
 
     /**
@@ -613,16 +618,21 @@ child:
     async SizeModeChanged(nsSizeMode sizeMode);
 
     async ParentActivated(bool aActivated);
 
     async SetKeyboardIndicators(UIStateChangeType showAccelerators,
                                 UIStateChangeType showFocusRings);
 
     /**
+     * Rolls up the popup in the child process
+     */
+    async RollupPopup();
+
+    /**
      * StopIMEStateManagement() is called when the process loses focus and
      * should stop managing IME state.
      */
     async StopIMEStateManagement();
 
     /**
      * @see nsIDOMWindowUtils sendMouseEvent.
      */
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -429,16 +429,17 @@ TabChild::TabChild(nsIContentChild* aMan
 #endif
   , mPendingDocShellIsActive(false)
   , mPendingDocShellReceivedMessage(false)
   , mPendingRenderLayers(false)
   , mPendingRenderLayersReceivedMessage(false)
   , mPendingLayerObserverEpoch(0)
   , mPendingDocShellBlockers(0)
   , mWidgetNativeData(0)
+  , mCombobox(nullptr)
 {
   mozilla::HoldJSObjects(this);
 
   nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this)));  // for capture by the lambda
   mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
                                                    const nsTArray<TouchBehaviorFlags>& aFlags)
   {
     if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
@@ -1315,16 +1316,31 @@ TabChild::RecvUpdateDimensions(const Dim
     mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeOffset.x,
                           screenRect.y + mClientOffset.y + mChromeOffset.y,
                           screenSize.width, screenSize.height, true);
 
     return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+TabChild::RecvRollupPopup()
+{
+  //At this point the child will know that we need to close the popup
+  //We will call rollup using the nsIRollupListener within nsCombobox
+  mCombobox->Rollup(0, false, nullptr, nullptr);
+  return IPC_OK();
+}
+
+void
+TabChild::SetCombobox(nsComboboxControlFrame* aCombobox)
+{
+  mCombobox = aCombobox;
+}
+
+mozilla::ipc::IPCResult
 TabChild::RecvSizeModeChanged(const nsSizeMode& aSizeMode)
 {
   mPuppetWidget->SetSizeMode(aSizeMode);
   if (!mPuppetWidget->IsVisible()) {
     return IPC_OK();
   }
   nsCOMPtr<nsIDocument> document(GetDocument());
   nsPresContext* presContext = document->GetPresContext();
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -15,16 +15,17 @@
 #include "nsIWebBrowserChrome2.h"
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsIWebBrowserChromeFocus.h"
 #include "nsIDOMEventListener.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIWindowProvider.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocShell.h"
+#include "nsComboboxControlFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsFrameMessageManager.h"
 #include "nsIPresShell.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsWeakReference.h"
 #include "nsITabChild.h"
 #include "nsITooltipListener.h"
 #include "mozilla/Attributes.h"
@@ -317,16 +318,21 @@ public:
   RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                     const layers::LayersId& aLayersId,
                     const mozilla::layers::CompositorOptions& aCompositorOptions,
                     const bool& aLayersConnected,
                     PRenderFrameChild* aRenderFrame) override;
 
   virtual mozilla::ipc::IPCResult
   RecvUpdateDimensions(const mozilla::dom::DimensionInfo& aDimensionInfo) override;
+
+  virtual mozilla::ipc::IPCResult RecvRollupPopup() override;
+
+  void SetCombobox(nsComboboxControlFrame* aCombobox);
+
   virtual mozilla::ipc::IPCResult
   RecvSizeModeChanged(const nsSizeMode& aSizeMode) override;
 
   mozilla::ipc::IPCResult RecvActivate();
 
   mozilla::ipc::IPCResult RecvDeactivate();
 
   MOZ_CAN_RUN_SCRIPT
@@ -914,16 +920,18 @@ private:
   bool mPendingRenderLayersReceivedMessage;
   uint64_t mPendingLayerObserverEpoch;
   // When mPendingDocShellBlockers is greater than 0, the DocShell is blocked,
   // and once it reaches 0, it is no longer blocked.
   uint32_t mPendingDocShellBlockers;
 
   WindowsHandle mWidgetNativeData;
 
+  nsComboboxControlFrame* mCombobox;
+
   // This state is used to keep track of the current visible tabs (the ones rendering
   // layers). There may be more than one if there are multiple browser windows open, or
   // tabs are being warmed up. There may be none if this process does not host any
   // visible or warming tabs.
   static nsTHashtable<nsPtrHashKey<TabChild>>* sVisibleTabs;
 
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -63,16 +63,18 @@
 #include "nsIWindowWatcher.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsIXULWindow.h"
 #include "nsIRemoteBrowser.h"
 #include "nsViewManager.h"
 #include "nsVariant.h"
 #include "nsIWidget.h"
+#include "nsIRollupListener.h"
+#include "SelectRollupListener.h"
 #include "nsNetUtil.h"
 #ifndef XP_WIN
 #include "nsJARProtocolHandler.h"
 #endif
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
@@ -154,16 +156,17 @@ TabParent::TabParent(nsIContentParent* a
   , mManager(aManager)
   , mDocShellIsActive(false)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mChromeFlags(aChromeFlags)
   , mDragValid(false)
   , mInitedByParent(false)
   , mTabId(aTabId)
+  , mListener(nullptr)
   , mCreatingWindow(false)
   , mCursor(eCursorInvalid)
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch(1)
@@ -391,16 +394,19 @@ TabParent::Destroy()
 
   if (XRE_IsParentProcess()) {
     ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->AsContentParent()->ChildID());
   } else {
     ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->ChildID());
   }
 
   mMarkedDestroying = true;
+
+  delete mListener;
+  mListener = nullptr;
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvEnsureLayersConnected(CompositorOptions* aCompositorOptions)
 {
   if (RenderFrameParent* frame = GetRenderFrame()) {
     frame->EnsureLayersConnected(aCompositorOptions);
   }
@@ -2528,16 +2534,46 @@ TabParent::RecvDispatchFocusToTopLevelWi
 {
   nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
   if (widget) {
     widget->SetFocus(false);
   }
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+TabParent::RecvCaptureRollupEvents(const LayoutDeviceIntRect& aRect, const bool& aDroppedDown)
+{
+  nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
+
+  if (aDroppedDown) {
+    if (mListener) {
+      mListener->SetRect(aRect);
+    } else {
+      SelectRollupListener* listener = new SelectRollupListener(this, aRect);
+      SetListener(listener);
+    }
+    nsBaseWidget::SetActiveRollupListener(mListener);
+    // widget->CaptureRollupEvents(mListener, true);
+  } else {
+    delete mListener;
+    mListener = nullptr;
+    nsBaseWidget::SetActiveRollupListener(mListener);
+    // widget->CaptureRollupEvents(mListener, false);
+  }
+
+  return IPC_OK();
+}
+
+void
+TabParent::SetListener(SelectRollupListener* aListener)
+{
+  mListener = aListener;
+}
+
 bool
 TabParent::ReceiveMessage(const nsString& aMessage,
                           bool aSync,
                           StructuredCloneData* aData,
                           CpowHolder* aCpows,
                           nsIPrincipal* aPrincipal,
                           nsTArray<StructuredCloneData>* aRetVal)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -27,16 +27,17 @@
 #include "nsIKeyEventInPluginCallback.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsRefreshDriver.h"
 #include "nsWeakReference.h"
 #include "Units.h"
 #include "nsIWidget.h"
+#include "SelectRollupListener.h"
 
 class nsFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsILoadContext;
 class nsIDocShell;
 class nsIWebBrowserPersistDocumentReceiver;
@@ -292,16 +293,18 @@ public:
 
   virtual mozilla::ipc::IPCResult RecvHideTooltip() override;
 
 
   virtual mozilla::ipc::IPCResult RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
 
   virtual mozilla::ipc::IPCResult RecvDispatchFocusToTopLevelWindow() override;
 
+  virtual mozilla::ipc::IPCResult RecvCaptureRollupEvents(const LayoutDeviceIntRect& aRect, const bool& aDroppedDown) override;
+
   virtual mozilla::ipc::IPCResult RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
                                                              const bool& aStartSwipe) override;
 
   virtual mozilla::ipc::IPCResult
   RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult
   RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent) override;
@@ -623,16 +626,18 @@ protected:
   virtual mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
                                                     const int32_t& aX, const int32_t& aY,
                                                     const int32_t& aCx, const int32_t& aCy) override;
 
   virtual mozilla::ipc::IPCResult RecvGetTabCount(uint32_t* aValue) override;
 
   virtual mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(const nsCString& aFirstPartyURI) override;
 
+  void SetListener(SelectRollupListener* aListener);
+
   ContentCacheInParent mContentCache;
 
   nsIntRect mRect;
   ScreenIntSize mDimensions;
   ScreenOrientationInternal mOrientation;
   float mDPI;
   int32_t mRounding;
   CSSToLayoutDeviceScale mDefaultScale;
@@ -690,16 +695,18 @@ private:
 
   // We keep a strong reference to the frameloader after we've sent the
   // Destroy message and before we've received __delete__. This allows us to
   // dispatch message manager messages during this time.
   RefPtr<nsFrameLoader> mFrameLoader;
 
   TabId mTabId;
 
+  SelectRollupListener* mListener;
+
   // When loading a new tab or window via window.open, the child is
   // responsible for loading the URL it wants into the new TabChild. When the
   // parent receives the CreateWindow message, though, it sends a LoadURL
   // message, usually for about:blank. It's important for the about:blank load
   // to get processed because the Firefox frontend expects every new window to
   // immediately start loading something (see bug 1123090). However, we want
   // the child to process the LoadURL message before it returns from
   // ProvideWindow so that the URL sent from the parent doesn't override the
--- a/layout/forms/moz.build
+++ b/layout/forms/moz.build
@@ -6,16 +6,17 @@
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Layout: Form Controls')
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 EXPORTS += [
+    'nsComboboxControlFrame.h',
     'nsIComboboxControlFrame.h',
     'nsIFormControlFrame.h',
     'nsIListControlFrame.h',
     'nsISelectControlFrame.h',
     'nsITextControlFrame.h',
 ]
 
 UNIFIED_SOURCES += [
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -9,16 +9,17 @@
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "nsCOMPtr.h"
 #include "nsFocusManager.h"
 #include "nsCheckboxRadioFrame.h"
 #include "nsGkAtoms.h"
+#include "nsCanvasFrame.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsHTMLParts.h"
 #include "nsIFormControl.h"
 #include "nsNameSpaceManager.h"
 #include "nsIListControlFrame.h"
 #include "nsPIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "mozilla/PresState.h"
@@ -46,25 +47,28 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Unused.h"
 #include "gfx2DGlue.h"
 #include "mozilla/widget/nsAutoRollup.h"
 #include "nsILayoutHistoryState.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/TabParent.h"
 
 #ifdef XP_WIN
 #define COMBOBOX_ROLLUP_CONSUME_EVENT 0
 #else
 #define COMBOBOX_ROLLUP_CONSUME_EVENT 1
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
+using namespace mozilla::dom;
 
 NS_IMETHODIMP
 nsComboboxControlFrame::RedisplayTextEvent::Run()
 {
   if (mControlFrame)
     mControlFrame->HandleRedisplayTextEvent();
   return NS_OK;
 }
@@ -303,16 +307,30 @@ nsComboboxControlFrame::SetFocus(bool aO
   InvalidateFrame();
 }
 
 void
 nsComboboxControlFrame::ShowPopup(bool aShowPopup)
 {
   // TODO(kuoe0) Remove this function when content-select is enabled.
 
+  if (nsLayoutUtils::IsContentSelectEnabled()) {
+    nsCanvasFrame* canvasFrame = do_QueryFrame(mDropdownFrame->GetParent());
+    if (aShowPopup){
+      mDroppedDown = true;
+      canvasFrame->SetDropdownFrame(mDropdownFrame);
+    } else {
+      PresShell()->FrameNeedsReflow(mDisplayFrame, nsIPresShell::eStyleChange,
+                                    NS_FRAME_IS_DIRTY);
+      mDroppedDown = false;
+      canvasFrame->SetDropdownFrame(nullptr);
+    }
+    return;
+  }
+
   nsView* view = mDropdownFrame->GetView();
   nsViewManager* viewManager = view->GetViewManager();
 
   if (aShowPopup) {
     nsRect rect = mDropdownFrame->GetRect();
     rect.x = rect.y = 0;
     viewManager->ResizeView(view, rect);
     viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
@@ -331,23 +349,28 @@ nsComboboxControlFrame::ShowPopup(bool a
 
     shell->HandleDOMEventWithTarget(mContent, &event, &status);
   }
 }
 
 bool
 nsComboboxControlFrame::ShowList(bool aShowList)
 {
-
-  // TODO(kuoe0) Remove this function when content-select is enabled.
-  //
-  // This function is used to handle the widget/view stuff, so we just return
-  // when content-select is enabled. And the following callee, ShowPopup(), will
-  // also be ignored, it is only used to show and hide the widget.
   if (nsLayoutUtils::IsContentSelectEnabled()) {
+    TabChild* tabChild = mozilla::dom::TabChild::GetFrom(PresContext()->GetPresShell());
+    if (aShowList) {
+      LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(mDropdownFrame->GetScreenRectInAppUnits(),
+                                  mDropdownFrame->PresContext()->AppUnitsPerDevPixel());
+      tabChild->SetCombobox(this);
+      tabChild->SendCaptureRollupEvents(rect, true);
+    } else {
+      tabChild->SetCombobox(nullptr);
+      tabChild->SendCaptureRollupEvents(LayoutDeviceIntRect(), false);
+    }
+    ShowPopup(aShowList);
     return true;
   }
 
   nsView* view = mDropdownFrame->GetView();
   if (aShowList) {
     NS_ASSERTION(!view->HasWidget(),
                  "We shouldn't have a widget before we need to display the popup");
 
@@ -584,17 +607,21 @@ public:
 };
 
 void
 nsComboboxControlFrame::GetAvailableDropdownSpace(WritingMode aWM,
                                                   nscoord* aBefore,
                                                   nscoord* aAfter,
                                                   LogicalPoint* aTranslation)
 {
-  MOZ_ASSERT(!XRE_IsContentProcess());
+  if (!nsLayoutUtils::IsContentSelectEnabled()) {
+    // TODO(kuoe0) remove this assertion after content-select is enabled
+     MOZ_ASSERT(!XRE_IsContentProcess());
+  }
+
   // Note: At first glance, it appears that you could simply get the
   // absolute bounding box for the dropdown list by first getting its
   // view, then getting the view's nsIWidget, then asking the nsIWidget
   // for its AbsoluteBounds.
   // The problem with this approach, is that the dropdown list's bcoord
   // location can change based on whether the dropdown is placed after
   // or before the display frame.  The approach taken here is to get the
   // absolute position of the display frame and use its location to
@@ -652,17 +679,18 @@ nsComboboxControlFrame::GetAvailableDrop
 
   *aAfter = after;
   *aBefore = before;
 }
 
 nsComboboxControlFrame::DropDownPositionState
 nsComboboxControlFrame::AbsolutelyPositionDropDown()
 {
-  if (XRE_IsContentProcess()) {
+  if (!nsLayoutUtils::IsContentSelectEnabled() && XRE_IsContentProcess()) {
+    // TODO(kuoe0) remove this after content-select is enabled
     return eDropDownPositionSuppressed;
   }
 
   WritingMode wm = GetWritingMode();
   LogicalPoint translation(wm);
   nscoord before, after;
   mLastDropDownAfterScreenBCoord = nscoord_MIN;
   GetAvailableDropdownSpace(wm, &before, &after, &translation);
@@ -692,18 +720,18 @@ nsComboboxControlFrame::AbsolutelyPositi
     // schedule a resize to show more rows if it has more rows to show.
     // (1.5 rows for good measure to avoid any rounding issues that would
     // lead to a loop of reflow requests)
     NS_DispatchToCurrentThread(new nsAsyncResize(this));
     return eDropDownPositionPendingResize;
   }
 
   // Position the drop-down after if there is room, otherwise place it before
-  // if there is room.  If there is no room for it on either side then place
-  // it after (to avoid overlapping UI like the URL bar).
+  // if there is room. If there is no room for it on either side then place
+  // it after (to avoid overlapping UI like the URL bar)
   bool b = dropdownSize.BSize(wm)<= after || dropdownSize.BSize(wm) > before;
   LogicalPoint dropdownPosition(wm, 0, b ? BSize(wm) : -dropdownSize.BSize(wm));
 
   // Don't position the view unless the position changed since it might cause
   // a call to NotifyGeometryChange() and an infinite loop here.
   nsSize containerSize = GetSize();
   const LogicalPoint currentPos =
     mDropdownFrame->GetLogicalPosition(containerSize);
@@ -1186,16 +1214,23 @@ nsComboboxControlFrame::HandleEvent(nsPr
   }
 #endif
 
   // If we have style that affects how we are selected, feed event down to
   // nsFrame::HandleEvent so that selection takes place when appropriate.
   if (IsContentDisabled()) {
     return nsBlockFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
   }
+
+  // We handle the drop-down and roll-up actions here.
+  if (nsLayoutUtils::IsContentSelectEnabled() &&
+      aEvent->mMessage == eMouseDown) {
+    ShowDropDown(!mDroppedDown);
+  }
+
   return NS_OK;
 }
 
 
 nsresult
 nsComboboxControlFrame::SetFormProperty(nsAtom* aName, const nsAString& aValue)
 {
   nsIFormControlFrame* fcFrame = do_QueryFrame(mDropdownFrame);
@@ -1434,16 +1469,19 @@ nsComboboxControlFrame::DestroyFrom(nsIF
     nsView* view = mDropdownFrame->GetView();
     MOZ_ASSERT(view);
     nsIWidget* widget = view->GetWidget();
     if (widget) {
       widget->CaptureRollupEvents(this, false);
     }
   }
 
+  nsCanvasFrame* canvasFrame = do_QueryFrame(mDropdownFrame->GetParent());
+  canvasFrame->SetDropdownFrame(nullptr);
+
   // Cleanup frames in popup child list
   mPopupFrames.DestroyFramesFrom(aDestructRoot, aPostDestroyData);
   aPostDestroyData.AddAnonymousContent(mDisplayContent.forget());
   aPostDestroyData.AddAnonymousContent(mButtonContent.forget());
   nsBlockFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
 }
 
 const nsFrameList&
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -176,16 +176,22 @@ nsListControlFrame::BuildDisplayList(nsD
   // XXX why do we need this here? we should never reach this. Maybe
   // because these can have widgets? Hmm
   if (aBuilder->IsBackgroundOnly())
     return;
 
   DO_GLOBAL_REFLOW_COUNT_DSP("nsListControlFrame");
 
   if (IsInDropDownMode()) {
+    if (nsLayoutUtils::IsContentSelectEnabled() &&
+      !mComboboxFrame->IsDroppedDown()) {
+      // Don't build the display list when the list is not dropped down.
+      return;
+    }
+
     NS_ASSERTION(NS_GET_A(mLastDropdownBackstopColor) == 255,
                  "need an opaque backstop color");
     // XXX Because we have an opaque widget and we get called to paint with
     // this frame as the root of a stacking context we need make sure to draw
     // some opaque color over the whole widget. (Bug 511323)
     aLists.BorderBackground()->AppendToBottom(
       MakeDisplayItem<nsDisplaySolidColor>(aBuilder,
         this, nsRect(aBuilder->ToReferenceFrame(this), GetSize()),
@@ -567,17 +573,17 @@ nsListControlFrame::ReflowAsDropdown(nsP
   // we're depending on?
   nsHTMLScrollFrame::DidReflow(aPresContext, &state);
 
   // Now compute the block size we want to have.
   // Note: no need to apply min/max constraints, since we have no such
   // rules applied to the combobox dropdown.
 
   mDropdownCanGrow = false;
-  if (visibleBSize <= 0 || blockSizeOfARow <= 0 || XRE_IsContentProcess()) {
+  if (visibleBSize <= 0 || blockSizeOfARow <= 0 || XRE_IsContentProcess) {
     // Looks like we have no options.  Just size us to a single row
     // block size.
     state.SetComputedBSize(blockSizeOfARow);
     mNumDisplayRows = 1;
   } else {
     nsComboboxControlFrame* combobox =
       static_cast<nsComboboxControlFrame*>(mComboboxFrame);
     LogicalPoint translation(wm);
@@ -1831,16 +1837,19 @@ nsListControlFrame::MouseDown(dom::Event
     CaptureMouseEvents(true);
     AutoWeakFrame weakFrame(this);
     bool change =
       HandleListSelection(aMouseEvent, selectedIndex); // might destroy us
     if (!weakFrame.IsAlive()) {
       return NS_OK;
     }
     mChangesSinceDragStart = change;
+  } else if (nsLayoutUtils::IsContentSelectEnabled()) {
+    // We handle the drop-down and roll-up action in the combo box.
+    return NS_OK;
   } else {
     // NOTE: the combo box is responsible for dropping it down
     if (mComboboxFrame) {
       // Ignore the click that occurs on the option element when one is
       // selected from the parent process popup.
       if (mComboboxFrame->IsOpenInParentProcess()) {
         nsCOMPtr<nsIContent> econtent =
           do_QueryInterface(aMouseEvent->GetTarget());
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -177,16 +177,22 @@ ViewportFrame::BuildDisplayListForTopLay
         BuildDisplayListForTopLayerFrame(aBuilder, backdropFrame, aList);
       }
       BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
     }
   }
 
   nsIPresShell* shell = PresShell();
   if (nsCanvasFrame* canvasFrame = shell->GetCanvasFrame()) {
+    // Build display items for the dropped-down menu
+    if (nsIFrame* dropdownFrame = canvasFrame->GetDropdownFrame()) {
+      BuildDisplayListForTopLayerFrame(aBuilder, dropdownFrame, aList);
+      MOZ_ASSERT(dropdownFrame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_TOP);
+    }
+
     if (Element* container = canvasFrame->GetCustomContentContainer()) {
       if (nsIFrame* frame = container->GetPrimaryFrame()) {
         MOZ_ASSERT(frame->StyleDisplay()->mTopLayer != NS_STYLE_TOP_LAYER_NONE,
                    "ua.css should ensure this");
         MOZ_ASSERT(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW);
         BuildDisplayListForTopLayerFrame(aBuilder, frame, aList);
       }
     }
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -63,35 +63,39 @@ with Files('Sticky*'):
 
 with Files('nsPluginFrame.*'):
     BUG_COMPONENT = ('Core', 'Plug-ins')
 
 with Files('nsVideoFrame.*'):
     BUG_COMPONENT = ('Core', 'Audio/Video')
 
 EXPORTS += [
+    'nsBlockFrame.h',
     'nsCanvasFrame.h',
     'nsContainerFrame.h',
     'nsDirection.h',
+    'nsFloatManager.h',
     'nsFrame.h',
     'nsFrameIdList.h',
     'nsFrameList.h',
     'nsFrameSelection.h',
     'nsFrameState.h',
     'nsFrameStateBits.h',
     'nsHTMLParts.h',
     'nsIAnonymousContentCreator.h',
     'nsIFrame.h',
     'nsIFrameInlines.h',
     'nsILineIterator.h',
+    'nsIntervalSet.h',
     'nsIObjectFrame.h',
     'nsIPageSequenceFrame.h',
     'nsIScrollableFrame.h',
     'nsIScrollPositionListener.h',
     'nsIStatefulFrame.h',
+    'nsLineBox.h',
     'nsPluginFrame.h',
     'nsQueryFrame.h',
     'nsRubyBaseContainerFrame.h',
     'nsRubyBaseFrame.h',
     'nsRubyFrame.h',
     'nsRubyTextContainerFrame.h',
     'nsRubyTextFrame.h',
     'nsSplittableFrame.h',
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -258,16 +258,25 @@ nsRect nsCanvasFrame::CanvasArea() const
   if (scrollableFrame) {
     nsRect portRect = scrollableFrame->GetScrollPortRect();
     result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size()));
   }
   return result;
 }
 
 void
+nsCanvasFrame::SetDropdownFrame(nsIFrame* aDropdownFrame) {
+  if (aDropdownFrame) {
+    MOZ_ASSERT(aDropdownFrame->IsListControlFrame(),
+               "Only nsListControlFrame can be dropped down.");
+  }
+  mDropdownFrame = aDropdownFrame;
+}
+
+void
 nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
                                       gfxContext* aCtx)
 {
   nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
   nsPoint offset = ToReferenceFrame();
   nsRect bgClipRect = frame->CanvasArea() + offset;
   if (NS_GET_A(mColor) > 0) {
     DrawTarget* drawTarget = aCtx->GetDrawTarget();
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -33,16 +33,17 @@ class nsCanvasFrame final : public nsCon
                             public nsIScrollPositionListener,
                             public nsIAnonymousContentCreator
 {
 public:
   explicit nsCanvasFrame(ComputedStyle* aStyle)
     : nsContainerFrame(aStyle, kClassID)
     , mDoPaintFocus(false)
     , mAddedScrollPositionListener(false)
+    , mDropdownFrame(nullptr)
   {}
 
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS(nsCanvasFrame)
 
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
 
@@ -108,26 +109,33 @@ public:
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
   virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
                                       nsIContent** aContent) override;
 
   nsRect CanvasArea() const;
 
+  // The frame should be dropped down
+  nsIFrame* GetDropdownFrame() const { return mDropdownFrame; }
+  void SetDropdownFrame(nsIFrame* aDropDownFrame);
+
 protected:
   // Utility function to propagate the WritingMode from our first child to
   // 'this' and all its ancestors.
   void MaybePropagateRootElementWritingMode();
 
   // Data members
   bool                      mDoPaintFocus;
   bool                      mAddedScrollPositionListener;
 
   nsCOMPtr<mozilla::dom::Element> mCustomContentContainer;
+
+private:
+  nsIFrame* mDropdownFrame;
 };
 
 /**
  * Override nsDisplayBackground methods so that we pass aBGClipRect to
  * PaintBackground, covering the whole overflow area.
  * We can also paint an "extra background color" behind the normal
  * background.
  */
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -9,16 +9,17 @@
 #ifndef nsLineBox_h___
 #define nsLineBox_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 
 #include "nsILineIterator.h"
 #include "nsIFrame.h"
+#include "X11UndefineNone.h"
 #include <algorithm>
 
 class nsLineBox;
 class nsFloatCache;
 class nsFloatCacheList;
 class nsFloatCacheFreeList;
 
 // State cached after reflowing a float. This state is used during
new file mode 100644
--- /dev/null
+++ b/widget/SelectRollupListener.cpp
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SelectRollupListener.h"
+
+SelectRollupListener::SelectRollupListener(mozilla::dom::TabParent* aParent, LayoutDeviceIntRect aRect)
+{
+  mParent = aParent;
+  mRect = aRect;
+}
+
+nsIWidget* SelectRollupListener::GetRollupWidget()
+{
+  nsIWidget* widget = nullptr;
+  return widget;
+}
+
+bool
+SelectRollupListener::Rollup(uint32_t aCount, bool aFlush,
+                      const nsIntPoint* pos, nsIContent** aLastRolledUp)
+{
+  return mParent->SendRollupPopup();
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/widget/SelectRollupListener.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef SelectRollupListener_h__
+#define SelectRollupListener_h__
+
+#include "nsIRollupListener.h"
+#include "nsCOMPtr.h"
+#include "mozilla/widget/nsAutoRollup.h"
+
+class nsIWidget;
+
+class SelectRollupListener : public nsIRollupListener
+{
+
+public:
+  SelectRollupListener(mozilla::dom::TabParent* aParent, mozilla::LayoutDeviceIntRect aRect);
+
+  virtual ~SelectRollupListener() {}
+
+   //nsIRollupListener
+  /**
+   * Hide the dropdown menu and stop capturing mouse events.
+   * @note This method might destroy |this|.
+   */
+  virtual bool Rollup(uint32_t aCount, bool aFlush,
+                      const nsIntPoint* pos, nsIContent** aLastRolledUp) override;
+
+  virtual void NotifyGeometryChange() override
+    { return; }
+
+  /**
+   * A combobox should roll up if a mousewheel event happens outside of
+   * the popup area.
+   */
+  virtual bool ShouldRollupOnMouseWheelEvent() override
+    { return true; }
+
+  virtual bool ShouldConsumeOnMouseWheelEvent() override
+    { return false; }
+
+  /**
+   * A combobox should not roll up if activated by a mouse activate message
+   * (eg. X-mouse).
+   */
+  virtual bool ShouldRollupOnMouseActivate() override
+    { return false; }
+
+  virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) override
+    { return 0; }
+
+  virtual nsIWidget* GetRollupWidget() override;
+
+  void SetRect(mozilla::LayoutDeviceIntRect aRect)
+    { mRect = aRect; }
+
+  mozilla::LayoutDeviceIntRect GetRect()
+    { return mRect; }
+
+protected:
+  mozilla::LayoutDeviceIntRect mRect;
+  mozilla::dom::TabParent* mParent;
+};
+
+#endif // SelectRollupListener_h__
+
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -28,16 +28,17 @@
 #include "nsObjCExceptions.h"
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
 #include "nsToolkit.h"
 #include "nsCRT.h"
 
 #include "nsFontMetrics.h"
 #include "nsIRollupListener.h"
+#include "SelectRollupListener.h"
 #include "nsViewManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIFile.h"
 #include "nsILocalFileMac.h"
 #include "nsGfxCIID.h"
 #include "nsThemeConstants.h"
 #include "nsIWidgetListener.h"
 #include "nsIPresShell.h"
@@ -4079,30 +4080,44 @@ NSEvent* gLastDragMouseDownEvent = nil;
   [[NSDistributedNotificationCenter defaultCenter]
     postNotificationName:@"com.apple.HIToolbox.beginMenuTrackingNotification"
                   object:@"org.mozilla.gecko.PopupWindow"];
   [(PopupWindow*)popupWindow setIsContextMenu:YES];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+- (BOOL)IsEventOverSpace:(NSEvent*)theEvent : (nsIRollupListener*)aRollupListener
+{
+  nsCOMPtr<nsIWidget> rollupWidget = aRollupListener->GetRollupWidget();
+  if (!rollupWidget) {
+    SelectRollupListener* selectRollupListener = (SelectRollupListener*) aRollupListener;
+    if (selectRollupListener) {
+      LayoutDeviceIntRect rollupRect = selectRollupListener->GetRect();
+      double backingScale = mGeckoChild->BackingScaleFactor();
+      return nsCocoaUtils::IsEventOverRect(theEvent, rollupRect, backingScale);
+    }
+  } else {
+    NSWindow* currentPopup = static_cast<NSWindow*>(rollupWidget->GetNativeData(NS_NATIVE_WINDOW));
+    return nsCocoaUtils::IsEventOverWindow(theEvent, currentPopup);
+  }
+}
+
 // Returns true if the event should no longer be processed, false otherwise.
 // This does not return whether or not anything was rolled up.
 - (BOOL)maybeRollup:(NSEvent*)theEvent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   BOOL consumeEvent = NO;
 
   nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
   NS_ENSURE_TRUE(rollupListener, false);
-  nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
-  if (rollupWidget) {
-    NSWindow* currentPopup = static_cast<NSWindow*>(rollupWidget->GetNativeData(NS_NATIVE_WINDOW));
-    if (!nsCocoaUtils::IsEventOverWindow(theEvent, currentPopup)) {
+  if (rollupListener) {
+    if (![self IsEventOverSpace:theEvent :rollupListener]) {
       // event is not over the rollup window, default is to roll up
       bool shouldRollup = true;
 
       // check to see if scroll events should roll up the popup
       if ([theEvent type] == NSScrollWheel) {
         shouldRollup = rollupListener->ShouldRollupOnMouseWheelEvent();
         // consume scroll events that aren't over the popup
         // unless the popup is an arrow panel
--- a/widget/cocoa/nsCocoaUtils.h
+++ b/widget/cocoa/nsCocoaUtils.h
@@ -228,21 +228,25 @@ public:
 
   static mozilla::LayoutDeviceIntRect CocoaRectToGeckoRectDevPix(
     const NSRect& aCocoaRect, CGFloat aBackingScale);
 
   // Gives the location for the event in screen coordinates. Do not call this
   // unless the window the event was originally targeted at is still alive!
   // anEvent may be nil -- in that case the current mouse location is returned.
   static NSPoint ScreenLocationForEvent(NSEvent* anEvent);
-  
+
   // Determines if an event happened over a window, whether or not the event
   // is for the window. Does not take window z-order into account.
   static BOOL IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow);
 
+  // Determines if an event happened over the rect, specifically for select
+  // elements.
+  static BOOL IsEventOverRect(NSEvent* anEvent, LayoutDeviceIntRect aRect, double aScaleFactor);
+
   // Events are set up so that their coordinates refer to the window to which they
   // were originally sent. If we reroute the event somewhere else, we'll have
   // to get the window coordinates this way. Do not call this unless the window
   // the event was originally targeted at is still alive!
   static NSPoint EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow);
 
   // Compatibility wrappers for the -[NSEvent phase], -[NSEvent momentumPhase],
   // -[NSEvent hasPreciseScrollingDeltas] and -[NSEvent scrollingDeltaX/Y] APIs
--- a/widget/cocoa/nsCocoaUtils.mm
+++ b/widget/cocoa/nsCocoaUtils.mm
@@ -131,16 +131,37 @@ BOOL nsCocoaUtils::IsEventOverWindow(NSE
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   return NSPointInRect(ScreenLocationForEvent(anEvent), [aWindow frame]);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
+BOOL nsCocoaUtils::IsEventOverRect(NSEvent* anEvent, LayoutDeviceIntRect aRect, double aScaleFactor)
+{
+  //we need to convert both the event and rect to the same coordinate space
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
+
+  NSRect cocoaRect = DevPixelsToCocoaPoints(aRect, aScaleFactor);
+  NSPoint event = ScreenLocationForEvent(anEvent);
+  float eventY = MenuBarScreenHeight() - event.y;
+
+  float xMax = cocoaRect.origin.x + cocoaRect.size.width;
+  float yMax = cocoaRect.origin.y + cocoaRect.size.height;
+
+  if ((eventY >= cocoaRect.origin.y && eventY <= yMax) &&
+    (event.x >= cocoaRect.origin.x && event.x <= xMax)) {
+    return true;
+  }
+  return false;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
+}
+
 NSPoint nsCocoaUtils::EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   return nsCocoaUtils::ConvertPointFromScreen(aWindow, ScreenLocationForEvent(anEvent));
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0));
 }
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/TextEventDispatcher.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/WidgetUtils.h"
 #include "mozilla/dom/WheelEventBinding.h"
+#include "SelectRollupListener.h"
 #include <algorithm>
 
 #include "GeckoProfiler.h"
 
 #include "prlink.h"
 #include "nsGTKToolkit.h"
 #include "nsIRollupListener.h"
 #include "nsINode.h"
@@ -5244,73 +5245,92 @@ nsWindow::SetWindowDecoration(nsBorderSt
 }
 
 void
 nsWindow::HideWindowChrome(bool aShouldHide)
 {
     SetWindowDecoration(aShouldHide ? eBorderStyle_none : mBorderStyle);
 }
 
+static bool
+is_mouse_in_rect (LayoutDeviceIntRect aRect, gdouble aMouseX, gdouble aMouseY)
+{
+    if (aMouseX >= aRect.x && aMouseX <= aRect.XMost()
+        && aMouseY >= aRect.y && aMouseY <= aRect.YMost()) {
+      return true;
+    }
+
+    return false;
+}
+
+static bool
+is_event_over_space(nsIRollupListener* aRollupListener, gdouble aMouseX, gdouble aMouseY)
+{
+    nsCOMPtr<nsIWidget> rollupWidget = aRollupListener->GetRollupWidget();
+    if (!rollupWidget) {
+      SelectRollupListener* selectRollupListener = (SelectRollupListener*) aRollupListener;
+      if (selectRollupListener){
+        LayoutDeviceIntRect rollupRect = selectRollupListener->GetRect();
+        return is_mouse_in_rect(rollupRect, aMouseX, aMouseY);
+      }
+    } else {
+      auto *currentPopup = (GdkWindow*)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
+      return is_mouse_in_window(currentPopup, aMouseX, aMouseY);
+    }
+}
+
 bool
 nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY,
-                         bool aIsWheel, bool aAlwaysRollup)
+                          bool aIsWheel, bool aAlwaysRollup)
 {
     nsIRollupListener* rollupListener = GetActiveRollupListener();
-    nsCOMPtr<nsIWidget> rollupWidget;
-    if (rollupListener) {
-        rollupWidget = rollupListener->GetRollupWidget();
-    }
-    if (!rollupWidget) {
-        nsBaseWidget::gRollupListener = nullptr;
-        return false;
-    }
 
     bool retVal = false;
-    auto *currentPopup =
-        (GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
-    if (aAlwaysRollup || !is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
+    if (rollupListener) {
+      if (aAlwaysRollup || !is_event_over_space(rollupListener, aMouseX, aMouseY)) {
         bool rollup = true;
         if (aIsWheel) {
             rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
             retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
         }
         // if we're dealing with menus, we probably have submenus and
         // we don't want to rollup if the click is in a parent menu of
         // the current submenu
         uint32_t popupsToRollup = UINT32_MAX;
         if (!aAlwaysRollup) {
-            AutoTArray<nsIWidget*, 5> widgetChain;
-            uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
-            for (uint32_t i=0; i<widgetChain.Length(); ++i) {
-                nsIWidget* widget = widgetChain[i];
-                auto* currWindow =
-                    (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
-                if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
-                  // don't roll up if the mouse event occurred within a
-                  // menu of the same type. If the mouse event occurred
-                  // in a menu higher than that, roll up, but pass the
-                  // number of popups to Rollup so that only those of the
-                  // same type close up.
-                  if (i < sameTypeCount) {
-                    rollup = false;
-                  }
-                  else {
-                    popupsToRollup = sameTypeCount;
-                  }
-                  break;
+          AutoTArray<nsIWidget*, 5> widgetChain;
+          uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
+          for (uint32_t i=0; i<widgetChain.Length(); ++i) {
+              nsIWidget* widget = widgetChain[i];
+              auto* currWindow =
+                  (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
+              if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
+                // don't roll up if the mouse event occurred within a
+                // menu of the same type. If the mouse event occurred
+                // in a menu higher than that, roll up, but pass the
+                // number of popups to Rollup so that only those of the
+                // same type close up.
+                if (i < sameTypeCount) {
+                  rollup = false;
                 }
-            } // foreach parent menu widget
+                else {
+                  popupsToRollup = sameTypeCount;
+                }
+                break;
+              }
+          } // foreach parent menu widget
         } // if rollup listener knows about menus
 
         // if we've determined that we should still rollup, do it.
         bool usePoint = !aIsWheel && !aAlwaysRollup;
         IntPoint point = IntPoint::Truncate(aMouseX, aMouseY);
         if (rollup && rollupListener->Rollup(popupsToRollup, true, usePoint ? &point : nullptr, nullptr)) {
-            retVal = true;
+          retVal = true;
         }
+      }
     }
     return retVal;
 }
 
 /* static */
 bool
 nsWindow::DragInProgress(void)
 {
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -131,16 +131,17 @@ EXPORTS += [
     'nsIPluginWidget.h',
     'nsIPrintDialogService.h',
     'nsIRollupListener.h',
     'nsIWidget.h',
     'nsIWidgetListener.h',
     'nsWidgetInitData.h',
     'nsWidgetsCID.h',
     'PuppetWidget.h',
+    'SelectRollupListener.h',
 ]
 
 EXPORTS.mozilla += [
     'BasicEvents.h',
     'CommandList.h',
     'ContentCache.h',
     'ContentEvents.h',
     'EventClassList.h',
@@ -195,16 +196,17 @@ UNIFIED_SOURCES += [
     'nsPrintSettingsImpl.cpp',
     'nsSoundProxy.cpp',
     'nsTransferable.cpp',
     'nsXPLookAndFeel.cpp',
     'PuppetBidiKeyboard.cpp',
     'PuppetWidget.cpp',
     'Screen.cpp',
     'ScreenManager.cpp',
+    'SelectRollupListener.cpp',
     'SharedWidgetUtils.cpp',
     'TextEventDispatcher.cpp',
     'VsyncDispatcher.cpp',
     'WidgetEventImpl.cpp',
     'WidgetUtils.cpp',
 ]
 
 if CONFIG['OS_ARCH'] == 'Linux':
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1812,16 +1812,22 @@ nsBaseWidget::GetActiveRollupListener()
   // If set, then this is likely an <html:select> dropdown.
   if (gRollupListener)
     return gRollupListener;
 
   return nsXULPopupManager::GetInstance();
 }
 
 void
+nsBaseWidget::SetActiveRollupListener(nsIRollupListener* aRollupListener)
+{
+  gRollupListener = aRollupListener;
+}
+
+void
 nsBaseWidget::NotifyWindowDestroyed()
 {
   if (!mWidgetListener)
     return;
 
   nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
   nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
   if (xulWindow) {
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -393,16 +393,18 @@ public:
     RefPtr<BasicLayerManager> mLayerManager;
   };
   friend class AutoLayerManagerSetup;
 
   virtual bool            ShouldUseOffMainThreadCompositing();
 
   static nsIRollupListener* GetActiveRollupListener();
 
+  static void SetActiveRollupListener(nsIRollupListener* aRollupListener);
+
   void Shutdown();
 
 #if defined(XP_WIN)
   uint64_t CreateScrollCaptureContainer() override;
 #endif
 
   // These functions should be called at the start and end of a "live" widget
   // resize (i.e. when the window contents are repainting during the resize,
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -105,16 +105,17 @@
 #include "nsNativeCharsetUtils.h"
 #include "nsGkAtoms.h"
 #include "nsCRT.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsWidgetsCID.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsString.h"
+#include "SelectRollupListener.h"
 #include "mozilla/Services.h"
 #include "nsNativeThemeWin.h"
 #include "nsWindowsDllInterceptor.h"
 #include "nsLayoutUtils.h"
 #include "nsView.h"
 #include "nsIWindowMediator.h"
 #include "nsIServiceManager.h"
 #include "nsWindowGfx.h"
@@ -7882,16 +7883,49 @@ nsWindow::EventIsInsideWindow(nsWindow* 
   POINT mp;
   mp.x = GET_X_LPARAM(pos);
   mp.y = GET_Y_LPARAM(pos);
 
   // was the event inside this window?
   return static_cast<bool>(::PtInRect(&r, mp));
 }
 
+bool
+nsWindow::EventIsInsideRect(LayoutDeviceIntRect rollupRect)
+{
+  //Screenlocation for event:
+  DWORD pos = ::GetMessagePos();
+  POINT mp;
+  mp.x = GET_X_LPARAM(pos);
+  mp.y = GET_Y_LPARAM(pos);
+
+  if ((mp.y >= rollupRect.y && mp.y <= rollupRect.YMost()) &&
+    (mp.x >= rollupRect.x && mp.x <= rollupRect.XMost())) {
+    return true;
+  }
+  return false;
+}
+
+//static
+bool
+nsWindow::IsEventOverSpace(nsIRollupListener* aRollupListener) {
+  nsCOMPtr<nsIWidget> widget = aRollupListener->GetRollupWidget();
+  if (widget) {
+    nsWindow* popupWindow = static_cast<nsWindow*>(widget.get());
+    return EventIsInsideWindow(popupWindow);
+  } else {
+    if (aRollupListener) {
+      SelectRollupListener* rollupListener = (SelectRollupListener*) aRollupListener;
+      LayoutDeviceIntRect rect = rollupListener->GetRect();
+      return EventIsInsideRect(rect);
+    }
+  }
+  return false;
+}
+
 // static
 bool
 nsWindow::GetPopupsToRollup(nsIRollupListener* aRollupListener,
                             uint32_t* aPopupsToRollup)
 {
   // If we're dealing with menus, we probably have submenus and we don't want
   // to rollup some of them if the click is in a parent menu of the current
   // submenu.
@@ -7953,265 +7987,262 @@ nsWindow::DealWithPopups(HWND aWnd, UINT
   // XXX Why do we use the return value of WM_MOUSEACTIVATE for all messages?
   *aResult = MA_NOACTIVATE;
 
   if (!::IsWindowVisible(aWnd)) {
     return false;
   }
 
   nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
+  nsCOMPtr<nsIWidget> widget = rollupListener->GetRollupWidget();
   NS_ENSURE_TRUE(rollupListener, false);
 
-  nsCOMPtr<nsIWidget> popup = rollupListener->GetRollupWidget();
-  if (!popup) {
-    return false;
-  }
-
-  static bool sSendingNCACTIVATE = false;
-  static bool sPendingNCACTIVATE = false;
-  uint32_t popupsToRollup = UINT32_MAX;
-
-  bool consumeRollupEvent = false;
-
-  nsWindow* popupWindow = static_cast<nsWindow*>(popup.get());
-  UINT nativeMessage = WinUtils::GetNativeMessage(aMessage);
-  switch (nativeMessage) {
-    case WM_TOUCH:
-      if (!IsTouchSupportEnabled(aWnd)) {
-        // If APZ is disabled, don't allow touch inputs to dismiss popups. The
-        // compatibility mouse events will do it instead.
-        return false;
-      }
-      MOZ_FALLTHROUGH;
-    case WM_LBUTTONDOWN:
-    case WM_RBUTTONDOWN:
-    case WM_MBUTTONDOWN:
-    case WM_NCLBUTTONDOWN:
-    case WM_NCRBUTTONDOWN:
-    case WM_NCMBUTTONDOWN:
-      if (nativeMessage != WM_TOUCH &&
-          IsTouchSupportEnabled(aWnd) &&
-          MOUSE_INPUT_SOURCE() == MouseEventBinding::MOZ_SOURCE_TOUCH) {
-        // If any of these mouse events are really compatibility events that
-        // Windows is sending for touch inputs, then don't allow them to dismiss
-        // popups when APZ is enabled (instead we do the dismissing as part of
-        // WM_TOUCH handling which is more correct).
-        // If we don't do this, then when the user lifts their finger after a
-        // long-press, the WM_RBUTTONDOWN compatibility event that Windows sends
-        // us will dismiss the contextmenu popup that we displayed as part of
-        // handling the long-tap-up.
-        return false;
-      }
-      if (!EventIsInsideWindow(popupWindow) &&
-          GetPopupsToRollup(rollupListener, &popupsToRollup)) {
-        break;
-      }
-      return false;
-    case WM_POINTERDOWN:
-      {
-        WinPointerEvents pointerEvents;
-        if (!pointerEvents.ShouldRollupOnPointerEvent(nativeMessage, aWParam)) {
+  if (rollupListener) {
+    bool consumeEvent = false;
+    static bool sSendingNCACTIVATE = false;
+    static bool sPendingNCACTIVATE = false;
+    uint32_t popupsToRollup = UINT32_MAX;
+
+    bool consumeRollupEvent = false;
+
+    UINT nativeMessage = WinUtils::GetNativeMessage(aMessage);
+    switch (nativeMessage) {
+      case WM_TOUCH:
+        if (!IsTouchSupportEnabled(aWnd)) {
+          // If APZ is disabled, don't allow touch inputs to dismiss popups. The
+          // compatibility mouse events will do it instead.
+          return false;
+        }
+        MOZ_FALLTHROUGH;
+      case WM_LBUTTONDOWN:
+      case WM_RBUTTONDOWN:
+      case WM_MBUTTONDOWN:
+      case WM_NCLBUTTONDOWN:
+      case WM_NCRBUTTONDOWN:
+      case WM_NCMBUTTONDOWN:
+        if (nativeMessage != WM_TOUCH &&
+            IsTouchSupportEnabled(aWnd) &&
+            MOUSE_INPUT_SOURCE() == MouseEventBinding::MOZ_SOURCE_TOUCH) {
+          // If any of these mouse events are really compatibility events that
+          // Windows is sending for touch inputs, then don't allow them to dismiss
+          // popups when APZ is enabled (instead we do the dismissing as part of
+          // WM_TOUCH handling which is more correct).
+          // If we don't do this, then when the user lifts their finger after a
+          // long-press, the WM_RBUTTONDOWN compatibility event that Windows sends
+          // us will dismiss the contextmenu popup that we displayed as part of
+          // handling the long-tap-up.
           return false;
         }
-        if (!GetPopupsToRollup(rollupListener, &popupsToRollup)) {
+        if (!IsEventOverSpace(rollupListener) && GetPopupsToRollup(rollupListener, &popupsToRollup)) {
+          break;
+        }
+        return false;
+      case WM_POINTERDOWN:
+        {
+          WinPointerEvents pointerEvents;
+          if (!pointerEvents.ShouldRollupOnPointerEvent(nativeMessage, aWParam)) {
+            return false;
+          }
+          if (widget) {
+            if (!GetPopupsToRollup(rollupListener, &popupsToRollup)) {
+              return false;
+            }
+            nsWindow* popupWindow = static_cast<nsWindow*>(widget.get());
+            // Can't use EventIsInsideWindow to check whether the event is inside
+            // the popup window. It's because EventIsInsideWindow gets message
+            // coordinates by GetMessagePos, which returns physical screen
+            // coordinates at WM_POINTERDOWN.
+            POINT pt;
+            pt.x = GET_X_LPARAM(aLParam);
+            pt.y = GET_Y_LPARAM(aLParam);
+            RECT r;
+            ::GetWindowRect(popupWindow->mWnd, &r);
+            if (::PtInRect(&r, pt) != 0) {
+              // Don't roll up if the event is inside the popup window.
+              return false;
+            }
+          }
+        }
+        break;
+      case WM_MOUSEWHEEL:
+      case WM_MOUSEHWHEEL:
+        // We need to check if the popup thinks that it should cause closing
+        // itself when mouse wheel events are fired outside the rollup widget.
+        if (!IsEventOverSpace(rollupListener)){
+          // Check if we should consume this event even if we don't roll-up:
+          consumeRollupEvent =
+            rollupListener->ShouldConsumeOnMouseWheelEvent();
+          *aResult = MA_ACTIVATE;
+          if (rollupListener->ShouldRollupOnMouseWheelEvent() &&
+              GetPopupsToRollup(rollupListener, &popupsToRollup)) {
+            break;
+          }
+        }
+        return consumeRollupEvent;
+
+      case WM_ACTIVATEAPP:
+        break;
+
+      case WM_ACTIVATE:
+        // NOTE: Don't handle WA_INACTIVE for preventing popup taking focus
+        // because we cannot distinguish it's caused by mouse or not.
+        if (LOWORD(aWParam) == WA_ACTIVE && aLParam) {
+          nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
+          if (window && window->IsPopup()) {
+            // Cancel notifying widget listeners of deactivating the previous
+            // active window (see WM_KILLFOCUS case in ProcessMessage()).
+            sJustGotDeactivate = false;
+            // Reactivate the window later.
+            ::PostMessageW(aWnd, MOZ_WM_REACTIVATE, aWParam, aLParam);
+            return true;
+          }
+          // Don't rollup the popup when focus moves back to the parent window
+          // from a popup because such case is caused by strange mouse drivers.
+          nsWindow* prevWindow =
+            WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam));
+          if (prevWindow && prevWindow->IsPopup()) {
+            return false;
+          }
+        } else if (LOWORD(aWParam) == WA_INACTIVE) {
+          nsWindow* activeWindow =
+            WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam));
+          if (sPendingNCACTIVATE && NeedsToHandleNCActivateDelayed(aWnd)) {
+            // If focus moves to non-popup widget or focusable popup, the window
+            // needs to update its nonclient area.
+            if (!activeWindow || !activeWindow->IsPopup()) {
+              sSendingNCACTIVATE = true;
+              ::SendMessageW(aWnd, WM_NCACTIVATE, false, 0);
+              sSendingNCACTIVATE = false;
+            }
+            sPendingNCACTIVATE = false;
+          }
+          // If focus moves from/to popup, we don't need to rollup the popup
+          // because such case is caused by strange mouse drivers.
+          if (activeWindow) {
+            if (activeWindow->IsPopup()) {
+              return false;
+            }
+            nsWindow* deactiveWindow = WinUtils::GetNSWindowPtr(aWnd);
+            if (deactiveWindow && deactiveWindow->IsPopup()) {
+              return false;
+            }
+          }
+        } else if (LOWORD(aWParam) == WA_CLICKACTIVE) {
+          // If the WM_ACTIVATE message is caused by a click in a popup,
+          // we should not rollup any popups.
+          nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
+          if ((window && window->IsPopup()) ||
+              !GetPopupsToRollup(rollupListener, &popupsToRollup)) {
+            return false;
+          }
+        }
+        break;
+
+      case MOZ_WM_REACTIVATE:
+        // The previous active window should take back focus.
+        if (::IsWindow(reinterpret_cast<HWND>(aLParam))) {
+          ::SetForegroundWindow(reinterpret_cast<HWND>(aLParam));
+        }
+        return true;
+
+      case WM_NCACTIVATE:
+        if (!aWParam && !sSendingNCACTIVATE &&
+            NeedsToHandleNCActivateDelayed(aWnd)) {
+          // Don't just consume WM_NCACTIVATE. It doesn't handle only the
+          // nonclient area state change.
+          ::DefWindowProcW(aWnd, aMessage, TRUE, aLParam);
+          // Accept the deactivating because it's necessary to receive following
+          // WM_ACTIVATE.
+          *aResult = TRUE;
+          sPendingNCACTIVATE = true;
+          return true;
+        }
+        return false;
+
+      case WM_MOUSEACTIVATE:
+        if (!IsEventOverSpace(rollupListener) && GetPopupsToRollup(rollupListener, &popupsToRollup)) {
+          // WM_MOUSEACTIVATE may be caused by moving the mouse (e.g., X-mouse
+          // of TweakUI is enabled. Then, check if the popup should be rolled up
+          // with rollup listener. If not, just consume the message.
+          if (HIWORD(aLParam) == WM_MOUSEMOVE &&
+              !rollupListener->ShouldRollupOnMouseActivate()) {
+            return true;
+          }
+          // Otherwise, it should be handled by wndproc.
           return false;
         }
-        // Can't use EventIsInsideWindow to check whether the event is inside
-        // the popup window. It's because EventIsInsideWindow gets message
-        // coordinates by GetMessagePos, which returns physical screen
-        // coordinates at WM_POINTERDOWN.
+
+        // Prevent the click inside the popup from causing a change in window
+        // activation. Since the popup is shown non-activated, we need to eat any
+        // requests to activate the window while it is displayed. Windows will
+        // automatically activate the popup on the mousedown otherwise.
+        return true;
+
+      case WM_SHOWWINDOW:
+        // If the window is being minimized, close popups.
+        if (aLParam == SW_PARENTCLOSING) {
+          break;
+        }
+        return false;
+
+      case WM_KILLFOCUS:
+        // If focus moves to other window created in different process/thread,
+        // e.g., a plugin window, popups should be rolled up.
+        if (IsDifferentThreadWindow(reinterpret_cast<HWND>(aWParam))) {
+          break;
+        }
+        return false;
+
+      case WM_MOVING:
+      case WM_MENUSELECT:
+        break;
+
+      default:
+        return false;
+    }
+
+    // Only need to deal with the last rollup for left mouse down events.
+    NS_ASSERTION(!nsAutoRollup::GetLastRollup(), "last rollup is null");
+
+    if (nativeMessage == WM_TOUCH || nativeMessage == WM_LBUTTONDOWN || nativeMessage == WM_POINTERDOWN) {
+      nsIntPoint pos;
+      if (nativeMessage == WM_TOUCH) {
+        if (nsWindow* win = WinUtils::GetNSWindowPtr(aWnd)) {
+          pos = win->GetTouchCoordinates(aWParam, aLParam);
+        }
+      } else {
         POINT pt;
         pt.x = GET_X_LPARAM(aLParam);
         pt.y = GET_Y_LPARAM(aLParam);
-        RECT r;
-        ::GetWindowRect(popupWindow->mWnd, &r);
-        if (::PtInRect(&r, pt) != 0) {
-          // Don't roll up if the event is inside the popup window.
-          return false;
-        }
-      }
-      break;
-    case WM_MOUSEWHEEL:
-    case WM_MOUSEHWHEEL:
-      // We need to check if the popup thinks that it should cause closing
-      // itself when mouse wheel events are fired outside the rollup widget.
-      if (!EventIsInsideWindow(popupWindow)) {
-        // Check if we should consume this event even if we don't roll-up:
-        consumeRollupEvent =
-          rollupListener->ShouldConsumeOnMouseWheelEvent();
-        *aResult = MA_ACTIVATE;
-        if (rollupListener->ShouldRollupOnMouseWheelEvent() &&
-            GetPopupsToRollup(rollupListener, &popupsToRollup)) {
-          break;
-        }
+        ::ClientToScreen(aWnd, &pt);
+        pos = nsIntPoint(pt.x, pt.y);
       }
-      return consumeRollupEvent;
-
-    case WM_ACTIVATEAPP:
-      break;
-
-    case WM_ACTIVATE:
-      // NOTE: Don't handle WA_INACTIVE for preventing popup taking focus
-      // because we cannot distinguish it's caused by mouse or not.
-      if (LOWORD(aWParam) == WA_ACTIVE && aLParam) {
-        nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
-        if (window && window->IsPopup()) {
-          // Cancel notifying widget listeners of deactivating the previous
-          // active window (see WM_KILLFOCUS case in ProcessMessage()).
-          sJustGotDeactivate = false;
-          // Reactivate the window later.
-          ::PostMessageW(aWnd, MOZ_WM_REACTIVATE, aWParam, aLParam);
-          return true;
-        }
-        // Don't rollup the popup when focus moves back to the parent window
-        // from a popup because such case is caused by strange mouse drivers.
-        nsWindow* prevWindow =
-          WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam));
-        if (prevWindow && prevWindow->IsPopup()) {
-          return false;
-        }
-      } else if (LOWORD(aWParam) == WA_INACTIVE) {
-        nsWindow* activeWindow =
-          WinUtils::GetNSWindowPtr(reinterpret_cast<HWND>(aLParam));
-        if (sPendingNCACTIVATE && NeedsToHandleNCActivateDelayed(aWnd)) {
-          // If focus moves to non-popup widget or focusable popup, the window
-          // needs to update its nonclient area.
-          if (!activeWindow || !activeWindow->IsPopup()) {
-            sSendingNCACTIVATE = true;
-            ::SendMessageW(aWnd, WM_NCACTIVATE, false, 0);
-            sSendingNCACTIVATE = false;
-          }
-          sPendingNCACTIVATE = false;
-        }
-        // If focus moves from/to popup, we don't need to rollup the popup
-        // because such case is caused by strange mouse drivers.
-        if (activeWindow) {
-          if (activeWindow->IsPopup()) {
-            return false;
-          }
-          nsWindow* deactiveWindow = WinUtils::GetNSWindowPtr(aWnd);
-          if (deactiveWindow && deactiveWindow->IsPopup()) {
-            return false;
-          }
-        }
-      } else if (LOWORD(aWParam) == WA_CLICKACTIVE) {
-        // If the WM_ACTIVATE message is caused by a click in a popup,
-        // we should not rollup any popups.
-        nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
-        if ((window && window->IsPopup()) ||
-            !GetPopupsToRollup(rollupListener, &popupsToRollup)) {
-          return false;
-        }
-      }
-      break;
-
-    case MOZ_WM_REACTIVATE:
-      // The previous active window should take back focus.
-      if (::IsWindow(reinterpret_cast<HWND>(aLParam))) {
-        ::SetForegroundWindow(reinterpret_cast<HWND>(aLParam));
-      }
+
+      nsIContent* lastRollup;
+      consumeRollupEvent =
+        rollupListener->Rollup(popupsToRollup, true, &pos, &lastRollup);
+    } else {
+      consumeRollupEvent = rollupListener->Rollup(popupsToRollup, true, nullptr, nullptr);
+    }
+
+    // Tell hook to stop processing messages
+    sProcessHook = false;
+    sRollupMsgId = 0;
+    sRollupMsgWnd = nullptr;
+
+    // If we are NOT supposed to be consuming events, let it go through
+    if (consumeRollupEvent && nativeMessage != WM_RBUTTONDOWN) {
+      *aResult = MA_ACTIVATE;
       return true;
-
-    case WM_NCACTIVATE:
-      if (!aWParam && !sSendingNCACTIVATE &&
-          NeedsToHandleNCActivateDelayed(aWnd)) {
-        // Don't just consume WM_NCACTIVATE. It doesn't handle only the
-        // nonclient area state change.
-        ::DefWindowProcW(aWnd, aMessage, TRUE, aLParam);
-        // Accept the deactivating because it's necessary to receive following
-        // WM_ACTIVATE.
-        *aResult = TRUE;
-        sPendingNCACTIVATE = true;
-        return true;
-      }
-      return false;
-
-    case WM_MOUSEACTIVATE:
-      if (!EventIsInsideWindow(popupWindow) &&
-          GetPopupsToRollup(rollupListener, &popupsToRollup)) {
-        // WM_MOUSEACTIVATE may be caused by moving the mouse (e.g., X-mouse
-        // of TweakUI is enabled. Then, check if the popup should be rolled up
-        // with rollup listener. If not, just consume the message.
-        if (HIWORD(aLParam) == WM_MOUSEMOVE &&
-            !rollupListener->ShouldRollupOnMouseActivate()) {
-          return true;
-        }
-        // Otherwise, it should be handled by wndproc.
-        return false;
-      }
-
-      // Prevent the click inside the popup from causing a change in window
-      // activation. Since the popup is shown non-activated, we need to eat any
-      // requests to activate the window while it is displayed. Windows will
-      // automatically activate the popup on the mousedown otherwise.
-      return true;
-
-    case WM_SHOWWINDOW:
-      // If the window is being minimized, close popups.
-      if (aLParam == SW_PARENTCLOSING) {
-        break;
-      }
-      return false;
-
-    case WM_KILLFOCUS:
-      // If focus moves to other window created in different process/thread,
-      // e.g., a plugin window, popups should be rolled up.
-      if (IsDifferentThreadWindow(reinterpret_cast<HWND>(aWParam))) {
-        break;
-      }
-      return false;
-
-    case WM_MOVING:
-    case WM_MENUSELECT:
-      break;
-
-    default:
-      return false;
-  }
-
-  // Only need to deal with the last rollup for left mouse down events.
-  NS_ASSERTION(!nsAutoRollup::GetLastRollup(), "last rollup is null");
-
-  if (nativeMessage == WM_TOUCH || nativeMessage == WM_LBUTTONDOWN || nativeMessage == WM_POINTERDOWN) {
-    nsIntPoint pos;
-    if (nativeMessage == WM_TOUCH) {
-      if (nsWindow* win = WinUtils::GetNSWindowPtr(aWnd)) {
-        pos = win->GetTouchCoordinates(aWParam, aLParam);
-      }
-    } else {
-      POINT pt;
-      pt.x = GET_X_LPARAM(aLParam);
-      pt.y = GET_Y_LPARAM(aLParam);
-      ::ClientToScreen(aWnd, &pt);
-      pos = nsIntPoint(pt.x, pt.y);
-    }
-
-    nsIContent* lastRollup;
-    consumeRollupEvent =
-      rollupListener->Rollup(popupsToRollup, true, &pos, &lastRollup);
-    nsAutoRollup::SetLastRollup(lastRollup);
-  } else {
-    consumeRollupEvent =
-      rollupListener->Rollup(popupsToRollup, true, nullptr, nullptr);
-  }
-
-  // Tell hook to stop processing messages
-  sProcessHook = false;
-  sRollupMsgId = 0;
-  sRollupMsgWnd = nullptr;
-
-  // If we are NOT supposed to be consuming events, let it go through
-  if (consumeRollupEvent && nativeMessage != WM_RBUTTONDOWN) {
-    *aResult = MA_ACTIVATE;
-    return true;
-  }
-
+    }
+  }
   return false;
 }
 
+
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: Misc. utility methods and functions.
  **
  ** General use.
  **
  **************************************************************
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -413,16 +413,19 @@ protected:
                                                   MSGResult& aResult);
   LRESULT                 ProcessCharMessage(const MSG &aMsg,
                                              bool *aEventDispatched);
   LRESULT                 ProcessKeyUpMessage(const MSG &aMsg,
                                               bool *aEventDispatched);
   LRESULT                 ProcessKeyDownMessage(const MSG &aMsg,
                                                 bool *aEventDispatched);
   static bool             EventIsInsideWindow(nsWindow* aWindow);
+  static bool             EventIsInsideRect(LayoutDeviceIntRect aRect);
+  static bool             IsEventOverSpace(nsIRollupListener* aListener);
+  static bool             EventIsInsideRect(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aButtonRect);
   // Convert nsEventStatus value to a windows boolean
   static bool             ConvertStatus(nsEventStatus aStatus);
   static void             PostSleepWakeNotification(const bool aIsSleepMode);
   int32_t                 ClientMarginHitTestPoint(int32_t mx, int32_t my);
   TimeStamp               GetMessageTimeStamp(LONG aEventTime) const;
   static void             UpdateFirstEventTime(DWORD aEventTime);
   void                    FinishLiveResizing(ResizeState aNewState);
   nsIntPoint              GetTouchCoordinates(WPARAM wParam, LPARAM lParam);