Bug 869314: Fix missing dropmarkers in non-native styled combobox controls when overlay scrollbars are used.
authorStephen Pohl <spohl.mozilla.bugs@gmail.com>
Sun, 26 May 2013 14:40:16 -0700
changeset 133014 abd5a7fec8231f962fd3e585bc64b8b1511abf24
parent 133007 2b36716b4d27e0324f44a6fca1ddd63dfcfa9a7b
child 133015 1063a022f196534069aeafa9d9feae081a7c8512
push id24735
push userphilringnalda@gmail.com
push dateMon, 27 May 2013 16:44:55 +0000
treeherdermozilla-central@ae460fbc4d0e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs869314
milestone24.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 869314: Fix missing dropmarkers in non-native styled combobox controls when overlay scrollbars are used.
gfx/src/nsThemeConstants.h
layout/forms/nsComboboxControlFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIScrollableFrame.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/gfx/src/nsThemeConstants.h
+++ b/gfx/src/nsThemeConstants.h
@@ -152,16 +152,19 @@
 // The scrollbar track
 #define NS_THEME_SCROLLBAR_TRACK_HORIZONTAL                86
 #define NS_THEME_SCROLLBAR_TRACK_VERTICAL                  87
 
 // The scrollbar thumb
 #define NS_THEME_SCROLLBAR_THUMB_HORIZONTAL                88
 #define NS_THEME_SCROLLBAR_THUMB_VERTICAL                  89
 
+// A non-disappearing scrollbar.
+#define NS_THEME_SCROLLBAR_NON_DISAPPEARING                90
+
 // A textfield or text area
 #define NS_THEME_TEXTFIELD                                 95
 
 // The caret of a text area
 #define NS_THEME_TEXTFIELD_CARET                           96
 
 // A multiline text field
 #define NS_THEME_TEXTFIELD_MULTILINE                       97
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -51,16 +51,17 @@
 #include "nsThemeConstants.h"
 #include "nsAsyncDOMEvent.h"
 #include "nsRenderingContext.h"
 #include "mozilla/Preferences.h"
 #include "nsContentList.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 #include "nsTextNode.h"
+#include "mozilla/LookAndFeel.h"
 
 using namespace mozilla;
 
 NS_IMETHODIMP
 nsComboboxControlFrame::RedisplayTextEvent::Run()
 {
   if (mControlFrame)
     mControlFrame->HandleRedisplayTextEvent();
@@ -733,34 +734,42 @@ nsComboboxControlFrame::GetIntrinsicWidt
                                           nsLayoutUtils::IntrinsicWidthType aType)
 {
   // get the scrollbar width, we'll use this later
   nscoord scrollbarWidth = 0;
   nsPresContext* presContext = PresContext();
   if (mListControlFrame) {
     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     NS_ASSERTION(scrollable, "List must be a scrollable frame");
-    scrollbarWidth =
-      scrollable->GetDesiredScrollbarSizes(presContext, aRenderingContext).LeftRight();
+    scrollbarWidth = scrollable->GetNondisappearingScrollbarWidth(
+      presContext, aRenderingContext);
   }
 
   nscoord displayWidth = 0;
   if (MOZ_LIKELY(mDisplayFrame)) {
     displayWidth = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
                                                         mDisplayFrame,
                                                         aType);
   }
 
   if (mDropdownFrame) {
     nscoord dropdownContentWidth;
+    bool isUsingOverlayScrollbars =
+      LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0;
     if (aType == nsLayoutUtils::MIN_WIDTH) {
       dropdownContentWidth = mDropdownFrame->GetMinWidth(aRenderingContext);
+      if (isUsingOverlayScrollbars) {
+        dropdownContentWidth += scrollbarWidth;
+      }
     } else {
       NS_ASSERTION(aType == nsLayoutUtils::PREF_WIDTH, "Unexpected type");
       dropdownContentWidth = mDropdownFrame->GetPrefWidth(aRenderingContext);
+      if (isUsingOverlayScrollbars) {
+        dropdownContentWidth += scrollbarWidth;
+      }
     }
     dropdownContentWidth = NSCoordSaturatingSubtract(dropdownContentWidth,
                                                      scrollbarWidth,
                                                      nscoord_MAX);
 
     displayWidth = std::max(dropdownContentWidth, displayWidth);
   }
 
@@ -845,19 +854,18 @@ nsComboboxControlFrame::Reflow(nsPresCon
   nscoord buttonWidth;
   const nsStyleDisplay *disp = StyleDisplay();
   if (IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) {
     buttonWidth = 0;
   }
   else {
     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     NS_ASSERTION(scrollable, "List must be a scrollable frame");
-    buttonWidth =
-      scrollable->GetDesiredScrollbarSizes(PresContext(),
-                                           aReflowState.rendContext).LeftRight();
+    buttonWidth = scrollable->GetNondisappearingScrollbarWidth(
+      PresContext(), aReflowState.rendContext);
     if (buttonWidth > aReflowState.ComputedWidth()) {
       buttonWidth = 0;
     }
   }
 
   mDisplayWidth = aReflowState.ComputedWidth() - buttonWidth;
 
   nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState,
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -927,16 +927,50 @@ nsGfxScrollFrameInner::GetDesiredScrollb
     // We don't currently support any scripts that would require a scrollbar
     // at the top. (Are there any?)
     result.bottom = size.height;
   }
 
   return result;
 }
 
+nscoord
+nsGfxScrollFrameInner::GetNondisappearingScrollbarWidth(nsBoxLayoutState* aState)
+{
+  NS_ASSERTION(aState && aState->GetRenderingContext(),
+               "Must have rendering context in layout state for size "
+               "computations");
+
+  if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
+    // We're using overlay scrollbars, so we need to get the width that
+    // non-disappearing scrollbars would have.
+    nsITheme* theme = aState->PresContext()->GetTheme();
+    if (theme &&
+        theme->ThemeSupportsWidget(aState->PresContext(),
+                                   mVScrollbarBox,
+                                   NS_THEME_SCROLLBAR_NON_DISAPPEARING)) {
+      nsIntSize size;
+      nsRenderingContext* rendContext = aState->GetRenderingContext();
+      if (rendContext) {
+        bool canOverride = true;
+        theme->GetMinimumWidgetSize(rendContext,
+                                    mVScrollbarBox,
+                                    NS_THEME_SCROLLBAR_NON_DISAPPEARING,
+                                    &size,
+                                    &canOverride);
+        if (size.width) {
+          return aState->PresContext()->DevPixelsToAppUnits(size.width);
+        }
+      }
+    }
+  }
+
+  return GetDesiredScrollbarSizes(aState).LeftRight();
+}
+
 nsresult
 nsXULScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   return mInner.CreateAnonymousContent(aElements);
 }
 
 void
 nsXULScrollFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -230,16 +230,17 @@ public:
                                  const nsSize& aScrollPortSize) const;
 
   uint32_t GetScrollbarVisibility() const {
     return (mHasVerticalScrollbar ? nsIScrollableFrame::VERTICAL : 0) |
            (mHasHorizontalScrollbar ? nsIScrollableFrame::HORIZONTAL : 0);
   }
   nsMargin GetActualScrollbarSizes() const;
   nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState);
+  nscoord GetNondisappearingScrollbarWidth(nsBoxLayoutState* aState);
   bool IsLTR() const;
   bool IsScrollbarOnRight() const;
   bool IsScrollingActive() const { return mScrollingActive || ShouldBuildLayer(); }
   void ResetScrollPositionForLayerPixelAlignment()
   {
     mScrollPosForLayerPixelAlignment = GetScrollPosition();
   }
 
@@ -481,16 +482,21 @@ public:
   virtual nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) MOZ_OVERRIDE {
     return mInner.GetDesiredScrollbarSizes(aState);
   }
   virtual nsMargin GetDesiredScrollbarSizes(nsPresContext* aPresContext,
           nsRenderingContext* aRC) MOZ_OVERRIDE {
     nsBoxLayoutState bls(aPresContext, aRC, 0);
     return GetDesiredScrollbarSizes(&bls);
   }
+  virtual nscoord GetNondisappearingScrollbarWidth(nsPresContext* aPresContext,
+          nsRenderingContext* aRC) MOZ_OVERRIDE {
+    nsBoxLayoutState bls(aPresContext, aRC, 0);
+    return mInner.GetNondisappearingScrollbarWidth(&bls);
+  }
   virtual nsRect GetScrollPortRect() const MOZ_OVERRIDE {
     return mInner.GetScrollPortRect();
   }
   virtual nsPoint GetScrollPosition() const MOZ_OVERRIDE {
     return mInner.GetScrollPosition();
   }
   virtual nsPoint GetLogicalScrollPosition() const MOZ_OVERRIDE {
     return mInner.GetLogicalScrollPosition();
@@ -739,16 +745,21 @@ public:
   virtual nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) MOZ_OVERRIDE {
     return mInner.GetDesiredScrollbarSizes(aState);
   }
   virtual nsMargin GetDesiredScrollbarSizes(nsPresContext* aPresContext,
           nsRenderingContext* aRC) MOZ_OVERRIDE {
     nsBoxLayoutState bls(aPresContext, aRC, 0);
     return GetDesiredScrollbarSizes(&bls);
   }
+  virtual nscoord GetNondisappearingScrollbarWidth(nsPresContext* aPresContext,
+          nsRenderingContext* aRC) MOZ_OVERRIDE {
+    nsBoxLayoutState bls(aPresContext, aRC, 0);
+    return mInner.GetNondisappearingScrollbarWidth(&bls);
+  }
   virtual nsRect GetScrollPortRect() const MOZ_OVERRIDE {
     return mInner.GetScrollPortRect();
   }
   virtual nsPoint GetScrollPosition() const MOZ_OVERRIDE {
     return mInner.GetScrollPosition();
   }
   virtual nsPoint GetLogicalScrollPosition() const MOZ_OVERRIDE {
     return mInner.GetLogicalScrollPosition();
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -76,17 +76,21 @@ public:
   virtual nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) = 0;
   /**
    * Return the sizes of all scrollbars assuming that any scrollbars that could
    * be visible due to overflowing content, are. This can be called during reflow
    * of the scrolled contents.
    */
   virtual nsMargin GetDesiredScrollbarSizes(nsPresContext* aPresContext,
                                             nsRenderingContext* aRC) = 0;
-
+  /**
+   * Return the width for non-disappearing scrollbars.
+   */
+  virtual nscoord GetNondisappearingScrollbarWidth(nsPresContext* aPresContext,
+                                                   nsRenderingContext* aRC) = 0;
   /**
    * Get the area of the scrollport relative to the origin of this frame's
    * border-box.
    * This is the area of this frame minus border and scrollbars.
    */
   virtual nsRect GetScrollPortRect() const = 0;
   /**
    * Get the offset of the scrollport origin relative to the scrolled
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2841,17 +2841,21 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
     {
       *aIsOverridable = false;
 
       if (nsLookAndFeel::GetInt(
             nsLookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
         aResult->SizeTo(16, 16);
         break;
       }
-
+      // Intentional fallthrough to next case.
+    }
+
+    case NS_THEME_SCROLLBAR_NON_DISAPPEARING:
+    {
       // yeah, i know i'm cheating a little here, but i figure that it
       // really doesn't matter if the scrollbar is vertical or horizontal
       // and the width metric is a really good metric for every piece
       // of the scrollbar.
 
       nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
       if (!scrollbarFrame) return NS_ERROR_FAILURE;
 
@@ -3051,16 +3055,17 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
     case NS_THEME_SCROLLBAR_BUTTON_UP:
     case NS_THEME_SCROLLBAR_BUTTON_DOWN:
     case NS_THEME_SCROLLBAR_BUTTON_LEFT:
     case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
     case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
     case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
+    case NS_THEME_SCROLLBAR_NON_DISAPPEARING:
 
     case NS_THEME_DROPDOWN:
     case NS_THEME_DROPDOWN_BUTTON:
     case NS_THEME_DROPDOWN_TEXT:
     case NS_THEME_DROPDOWN_TEXTFIELD:
       return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
       break;