Bug 1343977 - Extract nsAutoRollup into a more self-contained class and clean it up some. No functional changes intended. r?enndeakin
This just decouples nsAutoRollup from the widget class, which it isn't really
bound to anyway because the internal data is static. We'll need to be able to
use nsAutoRollup independently in the next patch.
MozReview-Commit-ID: 1dxSLTr4g1K
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -43,16 +43,17 @@
#include <algorithm>
#include "nsTextNode.h"
#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"
#ifdef XP_WIN
#define COMBOBOX_ROLLUP_CONSUME_EVENT 0
#else
#define COMBOBOX_ROLLUP_CONSUME_EVENT 1
#endif
using namespace mozilla;
@@ -1144,18 +1145,17 @@ nsComboboxControlFrame::HandleEvent(nsPr
EventStates eventStates = mContent->AsElement()->State();
if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
return NS_OK;
}
#if COMBOBOX_ROLLUP_CONSUME_EVENT == 0
if (aEvent->mMessage == eMouseDown) {
- nsIWidget* widget = GetNearestWidget();
- if (widget && GetContent() == widget->GetLastRollup()) {
+ if (GetContent() == mozilla::widget::nsAutoRollup::GetLastRollup()) {
// This event did a Rollup on this control - prevent it from opening
// the dropdown again!
*aEventStatus = nsEventStatus_eConsumeNoDefault;
return NS_OK;
}
}
#endif
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -36,16 +36,17 @@
#include "nsIObserverService.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Services.h"
+#include "mozilla/widget/nsAutoRollup.h"
using namespace mozilla;
using namespace mozilla::dom;
static_assert(nsIDOMKeyEvent::DOM_VK_HOME == nsIDOMKeyEvent::DOM_VK_END + 1 &&
nsIDOMKeyEvent::DOM_VK_LEFT == nsIDOMKeyEvent::DOM_VK_END + 2 &&
nsIDOMKeyEvent::DOM_VK_UP == nsIDOMKeyEvent::DOM_VK_END + 3 &&
nsIDOMKeyEvent::DOM_VK_RIGHT == nsIDOMKeyEvent::DOM_VK_END + 4 &&
@@ -1805,18 +1806,17 @@ nsXULPopupManager::MayShowPopup(nsMenuPo
// Don't show popups that we already have in our popup chain
if (IsPopupOpen(aPopup->GetContent())) {
NS_WARNING("Refusing to show duplicate popup");
return false;
}
// if the popup was just rolled up, don't reopen it
- nsCOMPtr<nsIWidget> widget = aPopup->GetWidget();
- if (widget && widget->GetLastRollup() == aPopup->GetContent())
+ if (mozilla::widget::nsAutoRollup::GetLastRollup() == aPopup->GetContent())
return false;
nsCOMPtr<nsIDocShellTreeItem> dsti = aPopup->PresContext()->GetDocShell();
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(dsti);
if (!baseWin)
return false;
nsCOMPtr<nsIDocShellTreeItem> root;
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -124,30 +124,32 @@ EXPORTS.mozilla += [
'VsyncDispatcher.h',
'WidgetUtils.h',
]
EXPORTS.mozilla.widget += [
'CompositorWidget.h',
'IMEData.h',
'InProcessCompositorWidget.h',
+ 'nsAutoRollup.h',
'PuppetBidiKeyboard.h',
'WidgetMessageUtils.h',
'WindowSurface.h'
]
UNIFIED_SOURCES += [
'CompositorWidget.cpp',
'ContentCache.cpp',
'GfxDriverInfo.cpp',
'GfxInfoBase.cpp',
'GfxInfoCollector.cpp',
'GfxInfoWebGL.cpp',
'InProcessCompositorWidget.cpp',
'InputData.cpp',
+ 'nsAutoRollup.cpp',
'nsBaseAppShell.cpp',
'nsBaseScreen.cpp',
'nsClipboardHelper.cpp',
'nsClipboardProxy.cpp',
'nsColorPickerProxy.cpp',
'nsContentProcessWidgetFactory.cpp',
'nsDatePickerProxy.cpp',
'nsDragServiceProxy.cpp',
new file mode 100644
--- /dev/null
+++ b/widget/nsAutoRollup.cpp
@@ -0,0 +1,47 @@
+/* -*- 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 "mozilla/widget/nsAutoRollup.h"
+
+namespace mozilla {
+namespace widget {
+
+/*static*/ uint32_t nsAutoRollup::sCount = 0;
+/*static*/ StaticRefPtr<nsIContent> nsAutoRollup::sLastRollup;
+
+nsAutoRollup::nsAutoRollup()
+{
+ // remember if sLastRollup was null, and only clear it upon destruction
+ // if so. This prevents recursive usage of nsAutoRollup from clearing
+ // sLastRollup when it shouldn't.
+ mWasClear = !sLastRollup;
+ sCount++;
+}
+
+nsAutoRollup::~nsAutoRollup()
+{
+ if (sLastRollup && mWasClear) {
+ sLastRollup = nullptr;
+ }
+ sCount--;
+}
+
+/*static*/ void
+nsAutoRollup::SetLastRollup(nsIContent* aLastRollup)
+{
+ // There must be at least one nsAutoRollup on the stack.
+ MOZ_ASSERT(sCount);
+
+ sLastRollup = aLastRollup;
+}
+
+/*static*/ nsIContent*
+nsAutoRollup::GetLastRollup()
+{
+ return sLastRollup.get();
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/nsAutoRollup.h
@@ -0,0 +1,52 @@
+/* -*- 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 nsAutoRollup_h__
+#define nsAutoRollup_h__
+
+#include "mozilla/Attributes.h" // for MOZ_RAII
+#include "mozilla/StaticPtr.h" // for StaticRefPtr
+
+class nsIContent;
+
+namespace mozilla {
+namespace widget {
+
+// A situation can occur when a mouse event occurs over a menu label while the
+// menu popup is already open. The expected behaviour is to close the popup.
+// This happens by calling nsIRollupListener::Rollup before the mouse event is
+// processed. However, in cases where the mouse event is not consumed, this
+// event will then get targeted at the menu label causing the menu to open
+// again. To prevent this, we store in sLastRollup a reference to the popup
+// that was closed during the Rollup call, and prevent this popup from
+// reopening while processing the mouse event.
+// sLastRollup can only be set while an nsAutoRollup is in scope;
+// when it goes out of scope sLastRollup is cleared automatically.
+// As sLastRollup is static, it can be retrieved by calling
+// nsAutoRollup::GetLastRollup.
+class MOZ_RAII nsAutoRollup
+{
+public:
+ nsAutoRollup();
+ ~nsAutoRollup();
+
+ static void SetLastRollup(nsIContent* aLastRollup);
+ // Return the popup that was last rolled up, or null if there isn't one.
+ static nsIContent* GetLastRollup();
+
+private:
+ // Whether sLastRollup was clear when this nsAutoRollup
+ // was created.
+ bool mWasClear;
+
+ // The number of nsAutoRollup instances active.
+ static uint32_t sCount;
+ // The last rolled up popup.
+ static StaticRefPtr<nsIContent> sLastRollup;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // nsAutoRollup_h__
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -103,17 +103,16 @@ nsIRollupListener* nsBaseWidget::gRollup
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::ipc;
using namespace mozilla::widget;
using namespace mozilla;
using base::Thread;
-nsIContent* nsBaseWidget::mLastRollup = nullptr;
// Global user preference for disabling native theme. Used
// in NativeWindowTheme.
bool gDisableNativeTheme = false;
// Async pump timer during injected long touch taps
#define TOUCH_INJECT_PUMP_TIMER_MSEC 50
#define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
int32_t nsIWidget::sPointerIdCounter = 0;
@@ -136,31 +135,16 @@ WritingMode
IMENotification::SelectionChangeDataBase::GetWritingMode() const
{
return WritingMode(mWritingMode);
}
} // namespace widget
} // namespace mozilla
-nsAutoRollup::nsAutoRollup()
-{
- // remember if mLastRollup was null, and only clear it upon destruction
- // if so. This prevents recursive usage of nsAutoRollup from clearing
- // mLastRollup when it shouldn't.
- wasClear = !nsBaseWidget::mLastRollup;
-}
-
-nsAutoRollup::~nsAutoRollup()
-{
- if (nsBaseWidget::mLastRollup && wasClear) {
- NS_RELEASE(nsBaseWidget::mLastRollup);
- }
-}
-
NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget, nsISupportsWeakReference)
//-------------------------------------------------------------------------
//
// nsBaseWidget constructor
//
//-------------------------------------------------------------------------
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -27,17 +27,16 @@
#if defined(XP_WIN)
// Scroll capture constants
const uint32_t kScrollCaptureFillColor = 0xFFa0a0a0; // gray
const mozilla::gfx::SurfaceFormat kScrollCaptureFormat =
mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32;
#endif
class nsIContent;
-class nsAutoRollup;
class gfxContext;
namespace mozilla {
class CompositorVsyncDispatcher;
class LiveResizeListener;
#ifdef ACCESSIBILITY
namespace a11y {
@@ -107,17 +106,16 @@ public:
* All cross-platform behavior that all widgets need to implement
* should be placed in this class.
* (Note: widget implementations are not required to use this
* class, but it gives them a head start.)
*/
class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference
{
- friend class nsAutoRollup;
friend class DispatchWheelEventOnMainThread;
friend class mozilla::widget::InProcessCompositorWidget;
friend class mozilla::layers::RemoteCompositorSession;
protected:
typedef base::Thread Thread;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::SourceSurface SourceSurface;
@@ -461,21 +459,16 @@ protected:
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
nsEventStatus aApzResponse);
const LayoutDeviceIntRegion RegionFromArray(const nsTArray<LayoutDeviceIntRect>& aRects);
void ArrayFromRegion(const LayoutDeviceIntRegion& aRegion,
nsTArray<LayoutDeviceIntRect>& aRects);
- virtual nsIContent* GetLastRollup() override
- {
- return mLastRollup;
- }
-
virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
int32_t aNativeKeyCode,
uint32_t aModifierFlags,
const nsAString& aCharacters,
const nsAString& aUnmodifiedCharacters,
nsIObserver* aObserver) override
{
mozilla::widget::AutoObserverNotifier notifier(aObserver, "keyevent");
@@ -691,20 +684,16 @@ protected:
bool mUpdateCursor;
bool mUseAttachedEvents;
bool mIMEHasFocus;
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
bool mAccessibilityInUseFlag;
#endif
static nsIRollupListener* gRollupListener;
- // the last rolled up popup. Only set this when an nsAutoRollup is in scope,
- // so it can be cleared automatically.
- static nsIContent* mLastRollup;
-
struct InitialZoomConstraints {
InitialZoomConstraints(const uint32_t& aPresShellID,
const FrameMetrics::ViewID& aViewID,
const ZoomConstraints& aConstraints)
: mPresShellID(aPresShellID), mViewID(aViewID), mConstraints(aConstraints)
{
}
@@ -742,31 +731,9 @@ protected:
const nsIntRegion & aPaintEvent,
const char * aWidgetName,
int32_t aWindowID);
static bool debug_GetCachedBoolPref(const char* aPrefName);
#endif
};
-// A situation can occur when a mouse event occurs over a menu label while the
-// menu popup is already open. The expected behaviour is to close the popup.
-// This happens by calling nsIRollupListener::Rollup before the mouse event is
-// processed. However, in cases where the mouse event is not consumed, this
-// event will then get targeted at the menu label causing the menu to open
-// again. To prevent this, we store in mLastRollup a reference to the popup
-// that was closed during the Rollup call, and prevent this popup from
-// reopening while processing the mouse event.
-// mLastRollup should only be set while an nsAutoRollup is in scope;
-// when it goes out of scope mLastRollup is cleared automatically.
-// As mLastRollup is static, it can be retrieved by calling
-// nsIWidget::GetLastRollup on any widget.
-class nsAutoRollup
-{
- bool wasClear;
-
- public:
-
- nsAutoRollup();
- ~nsAutoRollup();
-};
-
#endif // nsBaseWidget_h__
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1451,21 +1451,16 @@ class nsIWidget : public nsISupports
* Returns false on any platform that does not support it.
*
* @param aResizerRect The resizer's rect in device pixels.
* @return Whether a resize widget is shown.
*/
virtual bool ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) = 0;
/**
- * Return the popup that was last rolled up, or null if there isn't one.
- */
- virtual nsIContent* GetLastRollup() = 0;
-
- /**
* Begin a window resizing drag, based on the event passed in.
*/
virtual MOZ_MUST_USE nsresult
BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent,
int32_t aHorizontal,
int32_t aVertical) = 0;
/**
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -130,16 +130,17 @@
#include "nsIWidgetListener.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/gfx/2D.h"
#include "nsToolkitCompsCID.h"
#include "nsIAppStartup.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/TextEvents.h" // For WidgetKeyboardEvent
#include "mozilla/TextEventDispatcherListener.h"
+#include "mozilla/widget/nsAutoRollup.h"
#include "mozilla/widget/WinNativeEventData.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsThemeConstants.h"
#include "nsBidiKeyboard.h"
#include "nsThemeConstants.h"
#include "gfxConfig.h"
#include "InProcessWinCompositorWidget.h"
@@ -7911,35 +7912,36 @@ nsWindow::DealWithPopups(HWND aWnd, UINT
case WM_MENUSELECT:
break;
default:
return false;
}
// Only need to deal with the last rollup for left mouse down events.
- NS_ASSERTION(!mLastRollup, "mLastRollup is null");
+ 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, &mLastRollup);
- NS_IF_ADDREF(mLastRollup);
+ 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;