Bug 879565 - Add metrofx support for overlay scrollbars. Patch also replaces various static overlay metrics with LookAndFeel values. (Debug osx assertions fixed.) r=mstange
☠☠ backed out by 77f2e8fc86ee ☠ ☠
authorJim Mathies <jmathies@mozilla.com>
Mon, 01 Jul 2013 21:42:00 -0500
changeset 137097 77bd60758c538335765b26c3e3a648833c3fefd3
parent 137096 f2d7f79796641cbf66230ecae4154dedf8957ddb
child 137098 83a2966d94fb1a4ed072592f784a2ea368beb81c
push id30393
push userjmathies@mozilla.com
push dateTue, 02 Jul 2013 02:42:13 +0000
treeherdermozilla-inbound@77bd60758c53 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs879565
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 879565 - Add metrofx support for overlay scrollbars. Patch also replaces various static overlay metrics with LookAndFeel values. (Debug osx assertions fixed.) r=mstange
layout/generic/ScrollbarActivity.cpp
layout/generic/ScrollbarActivity.h
toolkit/themes/windows/global/xulscrollbars.css
widget/LookAndFeel.h
widget/cocoa/nsLookAndFeel.mm
widget/windows/nsLookAndFeel.cpp
widget/xpwidgets/nsXPLookAndFeel.cpp
--- a/layout/generic/ScrollbarActivity.cpp
+++ b/layout/generic/ScrollbarActivity.cpp
@@ -9,26 +9,42 @@
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMElementCSSInlineStyle.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIFrame.h"
 #include "nsContentUtils.h"
 #include "nsAString.h"
 #include "nsQueryFrame.h"
 #include "nsComponentManagerUtils.h"
+#include "mozilla/LookAndFeel.h"
 
 namespace mozilla {
 namespace layout {
 
 NS_IMPL_ISUPPORTS1(ScrollbarActivity, nsIDOMEventListener)
 
 void
+ScrollbarActivity::QueryLookAndFeelVals()
+{
+  // Fade animation constants
+  mScrollbarFadeBeginDelay =
+    LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarFadeBeginDelay);
+  mScrollbarFadeDuration =
+    LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarFadeDuration);
+  // Controls whether we keep the mouse move listener so we can display the
+  // scrollbars whenever the user moves the mouse within the scroll area.
+  mDisplayOnMouseMove =
+    LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarDisplayOnMouseMove);
+}
+
+void
 ScrollbarActivity::Destroy()
 {
-  StopListeningForEvents();
+  StopListeningForScrollbarEvents();
+  StopListeningForScrollAreaEvents();
   UnregisterFromRefreshDriver();
   CancelFadeBeginTimer();
 }
 
 void
 ScrollbarActivity::ActivityOccurred()
 {
   ActivityStarted();
@@ -39,47 +55,45 @@ void
 ScrollbarActivity::ActivityStarted()
 {
   mNestedActivityCounter++;
   CancelFadeBeginTimer();
   if (!SetIsFading(false)) {
     return;
   }
   UnregisterFromRefreshDriver();
-  StartListeningForEvents();
+  StartListeningForScrollbarEvents();
+  StartListeningForScrollAreaEvents();
   SetIsActive(true);
 
   NS_ASSERTION(mIsActive, "need to be active during activity");
   NS_ASSERTION(!mIsFading, "must not be fading during activity");
-  NS_ASSERTION(!mFadeBeginTimer, "fade begin timer shouldn't be running");
 }
 
 void
 ScrollbarActivity::ActivityStopped()
 {
   NS_ASSERTION(IsActivityOngoing(), "activity stopped while none was going on");
   NS_ASSERTION(mIsActive, "need to be active during activity");
   NS_ASSERTION(!mIsFading, "must not be fading during ongoing activity");
-  NS_ASSERTION(!mFadeBeginTimer, "must not be waiting for fade during ongoing activity");
 
   mNestedActivityCounter--;
 
   if (!IsActivityOngoing()) {
     StartFadeBeginTimer();
 
     NS_ASSERTION(mIsActive, "need to be active right after activity");
     NS_ASSERTION(!mIsFading, "must not be fading right after activity");
-    NS_ASSERTION(mFadeBeginTimer, "fade begin timer should be running");
   }
 }
 
 NS_IMETHODIMP
 ScrollbarActivity::HandleEvent(nsIDOMEvent* aEvent)
 {
-  if (!mIsActive)
+  if (!mDisplayOnMouseMove && !mIsActive)
     return NS_OK;
 
   nsAutoString type;
   aEvent->GetType(type);
 
   if (type.EqualsLiteral("mousemove")) {
     // Mouse motions anywhere in the scrollable frame should keep the
     // scrollbars visible.
@@ -146,69 +160,87 @@ ScrollbarActivity::HandleEventForScrollb
       // Don't call HoveredScrollbar(nullptr) here because we want the hover
       // attribute to stick until the scrollbars are hidden.
     }
     *aStoredHoverState = newHoveredState;
   }
 }
 
 void
-ScrollbarActivity::StartListeningForEvents()
+ScrollbarActivity::StartListeningForScrollbarEvents()
 {
-  if (mListeningForEvents)
+  if (mListeningForScrollbarEvents)
+    return;
+
+  mHorizontalScrollbar = do_QueryInterface(GetHorizontalScrollbar());
+  mVerticalScrollbar = do_QueryInterface(GetVerticalScrollbar());
+
+  AddScrollbarEventListeners(mHorizontalScrollbar);
+  AddScrollbarEventListeners(mVerticalScrollbar);
+
+  mListeningForScrollbarEvents = true;
+}
+
+void
+ScrollbarActivity::StopListeningForScrollbarEvents()
+{
+  if (!mListeningForScrollbarEvents)
+    return;
+
+  RemoveScrollbarEventListeners(mHorizontalScrollbar);
+  RemoveScrollbarEventListeners(mVerticalScrollbar);
+
+  mHorizontalScrollbar = nullptr;
+  mVerticalScrollbar = nullptr;
+  mListeningForScrollbarEvents = false;
+}
+
+void
+ScrollbarActivity::StartListeningForScrollAreaEvents()
+{
+  if (mListeningForScrollAreaEvents)
     return;
 
   nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
-  nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget = do_QueryInterface(
-                                                   scrollArea->GetContent());
-  mHorizontalScrollbar = do_QueryInterface(GetHorizontalScrollbar());
-  mVerticalScrollbar = do_QueryInterface(GetVerticalScrollbar());
-
+  nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget
+    = do_QueryInterface(scrollArea->GetContent());
   if (scrollAreaTarget) {
     scrollAreaTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
                                        true);
   }
-  StartListeningForEventsOnScrollbar(mHorizontalScrollbar);
-  StartListeningForEventsOnScrollbar(mVerticalScrollbar);
-  mListeningForEvents = true;
+  mListeningForScrollAreaEvents = true;
 }
 
 void
-ScrollbarActivity::StartListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar)
+ScrollbarActivity::StopListeningForScrollAreaEvents()
+{
+  if (!mListeningForScrollAreaEvents)
+    return;
+
+  nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
+  nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget = do_QueryInterface(scrollArea->GetContent());
+  if (scrollAreaTarget) {
+    scrollAreaTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true);
+  }
+  mListeningForScrollAreaEvents = false;
+}
+
+void
+ScrollbarActivity::AddScrollbarEventListeners(nsIDOMEventTarget* aScrollbar)
 {
   if (aScrollbar) {
     aScrollbar->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
     aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true);
     aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true);
     aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true);
   }
 }
 
 void
-ScrollbarActivity::StopListeningForEvents()
-{
-  if (!mListeningForEvents)
-    return;
-
-  nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
-  nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget = do_QueryInterface(scrollArea->GetContent());
-
-  if (scrollAreaTarget) {
-    scrollAreaTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true);
-  }
-  StopListeningForEventsOnScrollbar(mHorizontalScrollbar);
-  StopListeningForEventsOnScrollbar(mVerticalScrollbar);
-
-  mHorizontalScrollbar = nullptr;
-  mVerticalScrollbar = nullptr;
-  mListeningForEvents = false;
-}
-
-void
-ScrollbarActivity::StopListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar)
+ScrollbarActivity::RemoveScrollbarEventListeners(nsIDOMEventTarget* aScrollbar)
 {
   if (aScrollbar) {
     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true);
     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, true);
     aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, true);
   }
 }
@@ -237,17 +269,20 @@ ScrollbarActivity::EndFade()
   NS_ASSERTION(mIsActive, "still need to be active at this point");
   NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade end timer cancelled when scrollbar activity started?");
 
   if (!SetIsFading(false)) {
     return;
   }
   SetIsActive(false);
   UnregisterFromRefreshDriver();
-  StopListeningForEvents();
+  StopListeningForScrollbarEvents();
+  if (!mDisplayOnMouseMove) {
+    StopListeningForScrollAreaEvents();
+  }
 
   NS_ASSERTION(!mIsActive, "should have gone inactive after fade end");
   NS_ASSERTION(!mIsFading, "shouldn't be fading anymore");
   NS_ASSERTION(!mFadeBeginTimer, "fade begin timer shouldn't be running");
 }
 
 void
 ScrollbarActivity::RegisterWithRefreshDriver()
@@ -367,29 +402,29 @@ ScrollbarActivity::SetIsFading(bool aNew
     }
   }
   return true;
 }
 
 void
 ScrollbarActivity::StartFadeBeginTimer()
 {
-  NS_ASSERTION(!mFadeBeginTimer, "timer already alive!");
-  mFadeBeginTimer = do_CreateInstance("@mozilla.org/timer;1");
+  if (!mFadeBeginTimer) {
+    mFadeBeginTimer = do_CreateInstance("@mozilla.org/timer;1");
+  }
   mFadeBeginTimer->InitWithFuncCallback(FadeBeginTimerFired, this,
-                                        kScrollbarFadeBeginDelay,
+                                        mScrollbarFadeBeginDelay,
                                         nsITimer::TYPE_ONE_SHOT);
 }
 
 void
 ScrollbarActivity::CancelFadeBeginTimer()
 {
   if (mFadeBeginTimer) {
     mFadeBeginTimer->Cancel();
-    mFadeBeginTimer = nullptr;
   }
 }
 
 void
 ScrollbarActivity::HoveredScrollbar(nsIContent* aScrollbar)
 {
   SetBooleanAttribute(GetHorizontalScrollbar(), nsGkAtoms::hover, false);
   SetBooleanAttribute(GetVerticalScrollbar(), nsGkAtoms::hover, false);
--- a/layout/generic/ScrollbarActivity.h
+++ b/layout/generic/ScrollbarActivity.h
@@ -58,20 +58,26 @@ namespace layout {
 class ScrollbarActivity : public nsIDOMEventListener,
                           public nsARefreshObserver {
 public:
   ScrollbarActivity(nsIScrollbarOwner* aScrollableFrame)
    : mScrollableFrame(aScrollableFrame)
    , mNestedActivityCounter(0)
    , mIsActive(false)
    , mIsFading(false)
-   , mListeningForEvents(false)
+   , mListeningForScrollbarEvents(false)
+   , mListeningForScrollAreaEvents(false)
    , mHScrollbarHovered(false)
    , mVScrollbarHovered(false)
-  {}
+   , mDisplayOnMouseMove(false)
+   , mScrollbarFadeBeginDelay(0)
+   , mScrollbarFadeDuration(0)
+  {
+    QueryLookAndFeelVals();
+  }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 
   virtual ~ScrollbarActivity() {}
 
   void Destroy();
 
@@ -80,66 +86,74 @@ public:
   void ActivityStopped();
 
   virtual void WillRefresh(TimeStamp aTime) MOZ_OVERRIDE;
 
   static void FadeBeginTimerFired(nsITimer* aTimer, void* aSelf) {
     reinterpret_cast<ScrollbarActivity*>(aSelf)->BeginFade();
   }
 
-  static const uint32_t kScrollbarFadeBeginDelay = 450; // milliseconds
-  static const uint32_t kScrollbarFadeDuration = 200; // milliseconds
-
 protected:
 
   bool IsActivityOngoing()
   { return mNestedActivityCounter > 0; }
   bool IsStillFading(TimeStamp aTime);
+  void QueryLookAndFeelVals();
 
   void HandleEventForScrollbar(const nsAString& aType,
                                nsIContent* aTarget,
                                nsIContent* aScrollbar,
                                bool* aStoredHoverState);
 
   void SetIsActive(bool aNewActive);
   bool SetIsFading(bool aNewFading); // returns false if 'this' was destroyed
 
   void BeginFade();
   void EndFade();
 
   void StartFadeBeginTimer();
   void CancelFadeBeginTimer();
-  void StartListeningForEvents();
-  void StartListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar);
-  void StopListeningForEvents();
-  void StopListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar);
+
+  void StartListeningForScrollbarEvents();
+  void StartListeningForScrollAreaEvents();
+  void StopListeningForScrollbarEvents();
+  void StopListeningForScrollAreaEvents();
+  void AddScrollbarEventListeners(nsIDOMEventTarget* aScrollbar);
+  void RemoveScrollbarEventListeners(nsIDOMEventTarget* aScrollbar);
+
   void RegisterWithRefreshDriver();
   void UnregisterFromRefreshDriver();
 
   bool UpdateOpacity(TimeStamp aTime); // returns false if 'this' was destroyed
   void HoveredScrollbar(nsIContent* aScrollbar);
 
   nsRefreshDriver* GetRefreshDriver();
   nsIContent* GetScrollbarContent(bool aVertical);
   nsIContent* GetHorizontalScrollbar() { return GetScrollbarContent(false); }
   nsIContent* GetVerticalScrollbar() { return GetScrollbarContent(true); }
 
-  static const TimeDuration FadeDuration() {
-    return TimeDuration::FromMilliseconds(kScrollbarFadeDuration);
+  const TimeDuration FadeDuration() {
+    return TimeDuration::FromMilliseconds(mScrollbarFadeDuration);
   }
 
   nsIScrollbarOwner* mScrollableFrame;
   TimeStamp mFadeBeginTime;
   nsCOMPtr<nsITimer> mFadeBeginTimer;
   nsCOMPtr<nsIDOMEventTarget> mHorizontalScrollbar; // null while inactive
   nsCOMPtr<nsIDOMEventTarget> mVerticalScrollbar;   // null while inactive
   int mNestedActivityCounter;
   bool mIsActive;
   bool mIsFading;
-  bool mListeningForEvents;
+  bool mListeningForScrollbarEvents;
+  bool mListeningForScrollAreaEvents;
   bool mHScrollbarHovered;
   bool mVScrollbarHovered;
+
+  // LookAndFeel values we load on creation
+  bool mDisplayOnMouseMove;
+  int mScrollbarFadeBeginDelay;
+  int mScrollbarFadeDuration;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif /* ScrollbarActivity_h___ */
--- a/toolkit/themes/windows/global/xulscrollbars.css
+++ b/toolkit/themes/windows/global/xulscrollbars.css
@@ -18,16 +18,28 @@ scrollbar {
   background: url("chrome://global/skin/scrollbar/slider.gif") scrollbar;
 }
 
 scrollbar[orient="vertical"] 
 {
    -moz-appearance: scrollbartrack-vertical;
 }
 
+@media all and (-moz-overlay-scrollbars) {
+  scrollbar {
+    position: relative;
+    z-index: 2147483647;
+  }
+
+  scrollbar:not([active="true"]),
+  scrollbar[disabled="true"] {
+    visibility: hidden;
+  }
+}
+
 /* ::::: borders for thumb and buttons ::::: */
 
 thumb,
 scrollbarbutton {
   border: 2px solid;
   -moz-border-top-colors: ThreeDLightShadow ThreeDHighlight;
   -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
   -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow;
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -356,31 +356,43 @@ public:
      */
     eIntID_OperatingSystemVersionIdentifier,
     /**
      * 0: scrollbar button repeats to scroll only when cursor is on the button.
      * 1: scrollbar button repeats to scroll even if cursor is outside of it.
      */
     eIntID_ScrollbarButtonAutoRepeatBehavior,
     /**
-     * Dealy before showing a tooltip.
+     * Delay before showing a tooltip.
      */
     eIntID_TooltipDelay,
     /*
      * A Boolean value to determine whether Mac OS X Lion style swipe animations
      * should be used.
      */
     eIntID_SwipeAnimationEnabled,
 
     /*
      * A boolean value indicating whether or not the device has a hardware
      * home button. Used on gaia to determine whether a home button
      * is shown.
      */
-    eIntID_PhysicalHomeButton
+     eIntID_PhysicalHomeButton,
+ 
+     /*
+      * Controls whether overlay scrollbars display when the user moves
+      * the mouse in a scrollable frame.
+      */
+     eIntID_ScrollbarDisplayOnMouseMove,
+ 
+     /*
+      * Overlay scrollbar animation constants.
+      */
+     eIntID_ScrollbarFadeBeginDelay,
+     eIntID_ScrollbarFadeDuration
   };
 
   /**
    * Windows themes we currently detect.
    */
   enum WindowsTheme {
     eWindowsTheme_Generic = 0, // unrecognized theme
     eWindowsTheme_Classic,
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -353,16 +353,25 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
       aResult = eScrollThumbStyle_Proportional;
       break;
     case eIntID_UseOverlayScrollbars:
       aResult = SystemWantsOverlayScrollbars() ? 1 : 0;
       break;
     case eIntID_AllowOverlayScrollbarsOverlap:
       aResult = AllowOverlayScrollbarsOverlap() ? 1 : 0;
       break;
+    case eIntID_ScrollbarDisplayOnMouseMove:
+      aResult = 0;
+      break;
+    case eIntID_ScrollbarFadeBeginDelay:
+      aResult = 450;
+      break;
+    case eIntID_ScrollbarFadeDuration:
+      aResult = 200;
+      break;
     case eIntID_TreeOpenDelay:
       aResult = 1000;
       break;
     case eIntID_TreeCloseDelay:
       aResult = 1000;
       break;
     case eIntID_TreeLazyScrollDelay:
       aResult = 150;
--- a/widget/windows/nsLookAndFeel.cpp
+++ b/widget/windows/nsLookAndFeel.cpp
@@ -477,16 +477,31 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
         aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
         break;
     case eIntID_ScrollbarButtonAutoRepeatBehavior:
         aResult = 0;
         break;
     case eIntID_SwipeAnimationEnabled:
         aResult = 0;
         break;
+    case eIntID_UseOverlayScrollbars:
+        aResult = (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro);
+        break;
+    case eIntID_AllowOverlayScrollbarsOverlap:
+        aResult = 0;
+        break;
+    case eIntID_ScrollbarDisplayOnMouseMove:
+        aResult = 1;
+        break;
+    case eIntID_ScrollbarFadeBeginDelay:
+        aResult = 2500;
+        break;
+    case eIntID_ScrollbarFadeDuration:
+        aResult = 350;
+        break;
     default:
         aResult = 0;
         res = NS_ERROR_FAILURE;
     }
   return res;
 }
 
 nsresult
--- a/widget/xpwidgets/nsXPLookAndFeel.cpp
+++ b/widget/xpwidgets/nsXPLookAndFeel.cpp
@@ -46,16 +46,25 @@ nsLookAndFeelIntPref nsXPLookAndFeel::sI
     eIntID_UseAccessibilityTheme,
     false, 0 },
   { "ui.menusCanOverlapOSBar",
     eIntID_MenusCanOverlapOSBar,
     false, 0 },
   { "ui.useOverlayScrollbars",
     eIntID_UseOverlayScrollbars,
     false, 0 },
+  { "ui.scrollbarDisplayOnMouseMove",
+    eIntID_ScrollbarDisplayOnMouseMove,
+    false, 0 },
+  { "ui.scrollbarFadeBeginDelay",
+    eIntID_ScrollbarFadeBeginDelay,
+    false, 0 },
+  { "ui.scrollbarFadeDuration",
+    eIntID_ScrollbarFadeDuration,
+    false, 0 },
   { "ui.showHideScrollbars",
     eIntID_ShowHideScrollbars,
     false, 0 },
   { "ui.skipNavigatingDisabledMenuItem",
     eIntID_SkipNavigatingDisabledMenuItem,
     false, 0 },
   { "ui.treeOpenDelay",
     eIntID_TreeOpenDelay,