Bug 672050 - Add Mac rendering for -moz-appearance: toolbarbutton. r=josh
☠☠ backed out by f93b95bbad77 ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Mon, 08 Aug 2011 16:42:45 +0200
changeset 74015 0a6140e88a2d3402706a64607142ead300d97265
parent 74014 1abd25fed7b221af88183a763343c03681ab75e6
child 74016 4fb70b8c389fb827c4084da8226a05787dc22061
child 74021 f93b95bbad77b894b5c1be2d6e43dd0ba6e2baf5
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersjosh
bugs672050
milestone8.0a1
Bug 672050 - Add Mac rendering for -moz-appearance: toolbarbutton. r=josh
widget/src/cocoa/nsNativeThemeCocoa.h
widget/src/cocoa/nsNativeThemeCocoa.mm
widget/src/xpwidgets/nsNativeTheme.cpp
widget/src/xpwidgets/nsNativeTheme.h
--- a/widget/src/cocoa/nsNativeThemeCocoa.h
+++ b/widget/src/cocoa/nsNativeThemeCocoa.h
@@ -46,16 +46,17 @@
 #include "nsIAtom.h"
 #include "nsILookAndFeel.h"
 #include "nsNativeTheme.h"
 #include "gfxASurface.h"
 
 @class CellDrawView;
 @class NSProgressBarCell;
 class nsDeviceContext;
+struct SegmentedControlRenderSettings;
 
 class nsNativeThemeCocoa : private nsNativeTheme,
                            public nsITheme
 {
 public:
   nsNativeThemeCocoa();
   virtual ~nsNativeThemeCocoa();
 
@@ -91,30 +92,34 @@ public:
   PRBool ThemeDrawsFocusForWidget(nsPresContext* aPresContext, nsIFrame* aFrame, PRUint8 aWidgetType);
   PRBool ThemeNeedsComboboxDropmarker();
   virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, PRUint8 aWidgetType);
 
 protected:  
 
   nsresult GetSystemColor(PRUint8 aWidgetType, nsILookAndFeel::nsColorID& aColorID);
   nsIntMargin RTLAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame);
+  nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
+  CGRect SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
+                               nsIFrame* aCurrent, nsIFrame* aRight);
 
   // Helpers for progressbar.
   double GetProgressValue(nsIFrame* aFrame);
   double GetProgressMaxValue(nsIFrame* aFrame);
 
   // HITheme drawing routines
   void DrawFrame(CGContextRef context, HIThemeFrameKind inKind,
                  const HIRect& inBoxRect, PRBool inReadOnly,
                  nsEventStates inState);
   void DrawProgress(CGContextRef context, const HIRect& inBoxRect,
                     PRBool inIsIndeterminate, PRBool inIsHorizontal,
                     double inValue, double inMaxValue, nsIFrame* aFrame);
-  void DrawTab(CGContextRef context, HIRect inBoxRect, nsEventStates inState,
-               nsIFrame* aFrame);
+  void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
+                   nsEventStates inState, nsIFrame* aFrame,
+                   const SegmentedControlRenderSettings& aSettings);
   void DrawTabPanel(CGContextRef context, const HIRect& inBoxRect, nsIFrame* aFrame);
   void DrawScale(CGContextRef context, const HIRect& inBoxRect,
                  nsEventStates inState, PRBool inDirection,
                  PRBool inIsReverse, PRInt32 inCurrentValue, PRInt32 inMinValue,
                  PRInt32 inMaxValue, nsIFrame* aFrame);
   void DrawCheckboxOrRadio(CGContextRef cgContext, PRBool inCheckbox,
                            const HIRect& inBoxRect, PRBool inSelected,
                            nsEventStates inState, nsIFrame* aFrame);
--- a/widget/src/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/src/cocoa/nsNativeThemeCocoa.mm
@@ -284,16 +284,26 @@ static NSControlSize CocoaSizeForEnum(PR
   if (enumControlSize == miniControlSize)
     return NSMiniControlSize;
   else if (enumControlSize == smallControlSize)
     return NSSmallControlSize;
   else
     return NSRegularControlSize;
 }
 
+static NSString* CUIControlSizeForCocoaSize(NSControlSize aControlSize)
+{
+  if (aControlSize == NSRegularControlSize)
+    return @"regular";
+  else if (aControlSize == NSSmallControlSize)
+    return @"small";
+  else
+    return @"mini";
+}
+
 static void InflateControlRect(NSRect* rect, NSControlSize cocoaControlSize, const float marginSet[][3][4])
 {
   if (!marginSet)
     return;
 
   static int osIndex = leopardOS;
   int controlSize = EnumSizeForCocoaSize(cocoaControlSize);
   const float* buttonMargins = marginSet[osIndex][controlSize];
@@ -333,16 +343,25 @@ static BOOL FrameIsInActiveWindow(nsIFra
   topLevelWidget->GetWindowType(windowType);
   if (windowType == eWindowType_popup)
     return YES;
   if ([win isSheet])
     return [win isKeyWindow];
   return [win isMainWindow] && ![win attachedSheet];
 }
 
+// Toolbar controls and content controls respond to different window
+// activeness states.
+static BOOL IsActive(nsIFrame* aFrame, BOOL aIsToolbarControl)
+{
+  if (aIsToolbarControl)
+    return [NativeWindowForFrame(aFrame) isMainWindow] || ![NSView focusView];
+  return FrameIsInActiveWindow(aFrame);
+}
+
 NS_IMPL_ISUPPORTS_INHERITED1(nsNativeThemeCocoa, nsNativeTheme, nsITheme)
 
 
 nsNativeThemeCocoa::nsNativeThemeCocoa()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   // provide a local autorelease pool, as this is called during startup
@@ -569,17 +588,17 @@ struct CellRenderSettings {
  * This is a helper method that returns the required NSControlSize given a size
  * and the size of the three controls plus a tolerance.
  * size - The width or the height of the element to draw.
  * sizes - An array with the all the width/height of the element for its
  *         different sizes.
  * tolerance - The tolerance as passed to DrawCellWithSnapping.
  * NOTE: returns NSRegularControlSize if all values in 'sizes' are zero.
  */
-static NSControlSize FindControlSize(CGFloat size, CGFloat* sizes, CGFloat tolerance)
+static NSControlSize FindControlSize(CGFloat size, const CGFloat* sizes, CGFloat tolerance)
 {
   for (PRUint32 i = miniControlSize; i <= regularControlSize; ++i) {
     if (sizes[i] == 0) {
       continue;
     }
 
     CGFloat next = 0;
     // Find next value.
@@ -1339,96 +1358,117 @@ nsNativeThemeCocoa::DrawScale(CGContextR
   tdi.trackInfo.slider.thumbDir = kThemeThumbPlain;
   tdi.trackInfo.slider.pressState = 0;
 
   HIThemeDrawTrack(&tdi, NULL, cgContext, HITHEME_ORIENTATION);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
-#define NATURAL_MINI_TAB_BUTTON_HEIGHT    17
-#define NATURAL_SMALL_TAB_BUTTON_HEIGHT   20
-#define NATURAL_REGULAR_TAB_BUTTON_HEIGHT 23
+nsIFrame*
+nsNativeThemeCocoa::SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter)
+{
+  // Usually a separator is drawn by the segment to the right of the
+  // separator, but pressed and selected segments have higher priority.
+  if (!aBefore || !aAfter)
+    return nsnull;
+  if (IsSelectedButton(aAfter))
+    return aAfter;
+  if (IsSelectedButton(aBefore) || IsPressedButton(aBefore))
+    return aBefore;
+  return aAfter;
+}
+
+CGRect
+nsNativeThemeCocoa::SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
+                                          nsIFrame* aCurrent, nsIFrame* aRight)
+{
+  // A separator between two segments should always be located in the leftmost
+  // pixel column of the segment to the right of the separator, regardless of
+  // who ends up drawing it.
+  // CoreUI draws the separators inside the drawing rect.
+  if (aLeft && SeparatorResponsibility(aLeft, aCurrent) == aLeft) {
+    // The left button draws the separator, so we need to make room for it.
+    aRect.origin.x += 1;
+    aRect.size.width -= 1;
+  }
+  if (SeparatorResponsibility(aCurrent, aRight) == aCurrent) {
+    // We draw the right separator, so we need to extend the draw rect into the
+    // segment to our right.
+    aRect.size.width += 1;
+  }
+  return aRect;
+}
+
+static NSString* ToolbarButtonPosition(BOOL aIsFirst, BOOL aIsLast)
+{
+  if (aIsFirst) {
+    if (aIsLast)
+      return @"kCUISegmentPositionOnly";
+    return @"kCUISegmentPositionFirst";
+  }
+  if (aIsLast)
+    return @"kCUISegmentPositionLast";
+  return @"kCUISegmentPositionMiddle";
+}
+
+struct SegmentedControlRenderSettings {
+  const CGFloat* heights;
+  const NSString* widgetName;
+  const BOOL ignoresPressedWhenSelected;
+  const BOOL isToolbarControl;
+};
+
+static const CGFloat tabHeights[3] = { 17, 20, 23 };
+
+static const SegmentedControlRenderSettings tabRenderSettings = {
+  tabHeights, @"tab", YES, NO
+};
+
+static const CGFloat toolbarButtonHeights[3] = { 15, 18, 22 };
+
+static const SegmentedControlRenderSettings toolbarButtonRenderSettings = {
+  toolbarButtonHeights, @"kCUIWidgetButtonSegmentedSCurve", NO, YES
+};
 
 void
-nsNativeThemeCocoa::DrawTab(CGContextRef cgContext, HIRect inBoxRect,
-                            nsEventStates inState, nsIFrame* aFrame)
+nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
+                                nsEventStates inState, nsIFrame* aFrame,
+                                const SegmentedControlRenderSettings& aSettings)
 {
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-
-  HIThemeTabDrawInfo tdi;
-  tdi.version = 1;
-  tdi.kind = kHIThemeTabKindNormal;
-
-  PRBool isSelected = IsSelectedTab(aFrame);
-  PRBool isDisabled = IsDisabled(aFrame, inState);
-
-  if (isSelected) {
-    if (isDisabled)
-      tdi.style = kThemeTabFrontUnavailable;
-    else
-      tdi.style = FrameIsInActiveWindow(aFrame) ? kThemeTabFront : kThemeTabFrontInactive;
-  } else {
-    if (isDisabled)
-      tdi.style = kThemeTabNonFrontUnavailable;
-    else if (inState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER))
-      tdi.style = kThemeTabNonFrontPressed;
-    else
-      tdi.style = FrameIsInActiveWindow(aFrame) ? kThemeTabNonFront : kThemeTabNonFrontInactive;
+  BOOL isActive = IsActive(aFrame, aSettings.isToolbarControl);
+  BOOL isFocused = inState.HasState(NS_EVENT_STATE_FOCUS);
+  BOOL isSelected = IsSelectedButton(aFrame);
+  BOOL isPressed = IsPressedButton(aFrame);
+  if (isSelected && aSettings.ignoresPressedWhenSelected) {
+    isPressed = NO;
   }
 
-  tdi.direction = kThemeTabNorth;
-  tdi.size = kHIThemeTabSizeNormal;
-  if (inBoxRect.size.height < NATURAL_REGULAR_TAB_BUTTON_HEIGHT)
-    tdi.size = kHIThemeTabSizeSmall;
-  if (inBoxRect.size.height < NATURAL_SMALL_TAB_BUTTON_HEIGHT)
-    tdi.size = kHIThemeTabSizeMini;
-
-  PRBool isRTL = IsFrameRTL(aFrame);
-  PRBool isFirst = isRTL ? IsLastTab(aFrame) : IsFirstTab(aFrame);
-  PRBool isLast = isRTL ? IsFirstTab(aFrame) : IsLastTab(aFrame);
-
-  if (isFirst && isLast)
-    tdi.position = kHIThemeTabPositionOnly;
-  else if (isFirst)
-    tdi.position = kHIThemeTabPositionFirst;
-  else if (isLast)
-    tdi.position = kHIThemeTabPositionLast;
-  else
-    tdi.position = kHIThemeTabPositionMiddle;
-
-  // Tab separator management:
-  // Normal tabs only draw their left separator, in the leftmost pixel row of
-  // their frame. Selected tabs additionally draw their right separator, outside
-  // of their frame. To prevent overlapping, the tab to the right of the
-  // selected tab shouldn't draw its left separator.
-  tdi.adornment = kHIThemeTabAdornmentNone;
-  if (isRTL ? IsBeforeSelectedTab(aFrame) : IsAfterSelectedTab(aFrame)) {
-    // On Leopard, the tab's left edge must be shifted 1px to the right.
-    // On Tiger, this happens automatically when no leading separator is drawn.
-    inBoxRect.origin.x += 1;
-    inBoxRect.size.width -= 1;
-  }
-  else {
-    tdi.adornment = kHIThemeTabAdornmentLeadingSeparator;
-  }
-
-  if (isSelected && !isLast) {
-    tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
-    // On Tiger, the right separator is drawn outside of the frame.
-    // On Leopard, the right edge must be shifted 1px to the right.
-    inBoxRect.size.width += 1;
-  }
-  
-  if (inState.HasState(NS_EVENT_STATE_FOCUS))
-    tdi.adornment |= kThemeAdornmentFocus;
-
-  HIThemeDrawTab(&inBoxRect, &tdi, cgContext, HITHEME_ORIENTATION, NULL);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK;
+  BOOL isRTL = IsFrameRTL(aFrame);
+  nsIFrame* left = GetAdjacentSiblingFrameWithSameAppearance(aFrame, isRTL);
+  nsIFrame* right = GetAdjacentSiblingFrameWithSameAppearance(aFrame, !isRTL);
+  CGRect drawRect = SeparatorAdjustedRect(inBoxRect, left, aFrame, right);
+  BOOL drawLeftSeparator = SeparatorResponsibility(left, aFrame) == aFrame;
+  BOOL drawRightSeparator = SeparatorResponsibility(aFrame, right) == aFrame;
+  NSControlSize controlSize = FindControlSize(drawRect.size.height, aSettings.heights, 4.0f);
+
+  CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
+          (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
+            aSettings.widgetName, @"widget",
+            ToolbarButtonPosition(!left, !right), @"kCUIPositionKey",
+            [NSNumber numberWithBool:drawLeftSeparator], @"kCUISegmentLeadingSeparatorKey",
+            [NSNumber numberWithBool:drawRightSeparator], @"kCUISegmentTrailingSeparatorKey",
+            [NSNumber numberWithBool:isSelected], @"value",
+            (isPressed ? @"pressed" : (isActive ? @"normal" : @"inactive")), @"state",
+            [NSNumber numberWithBool:isFocused], @"focus",
+            CUIControlSizeForCocoaSize(controlSize), @"size",
+            [NSNumber numberWithBool:YES], @"is.flipped",
+            @"up", @"direction",
+            nil],
+          nil);
 }
 
 static inline UInt8
 ConvertToPressState(nsEventStates aButtonState, UInt8 aPressState)
 {
   // If the button is pressed, return the press state passed in. Otherwise, return 0.
   return aButtonState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER) ? aPressState : 0;
 }
@@ -1624,33 +1664,31 @@ void
 nsNativeThemeCocoa::DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect,
                                   nsIFrame *aFrame)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (inBoxRect.size.height < 2.0f)
     return;
 
-  BOOL isMain = [NativeWindowForFrame(aFrame) isMainWindow] || ![NSView focusView];
-
   CGContextSaveGState(cgContext);
   CGContextClipToRect(cgContext, inBoxRect);
 
   // kCUIWidgetWindowFrame draws a complete window frame with both title bar
   // and bottom bar. We only want the bottom bar, so we extend the draw rect
   // upwards to make space for the title bar, and then we clip it away.
   CGRect drawRect = inBoxRect;
   const int extendUpwards = 40;
   drawRect.origin.y -= extendUpwards;
   drawRect.size.height += extendUpwards;
   CUIDraw([NSWindow coreUIRenderer], drawRect, cgContext,
           (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
             @"kCUIWidgetWindowFrame", @"widget",
             @"regularwin", @"windowtype",
-            (isMain ? @"normal" : @"inactive"), @"state",
+            (IsActive(aFrame, YES) ? @"normal" : @"inactive"), @"state",
             [NSNumber numberWithInt:inBoxRect.size.height], @"kCUIWindowFrameBottomBarHeightKey",
             [NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawBottomBarSeparatorKey",
             [NSNumber numberWithBool:YES], @"is.flipped",
             nil],
           nil);
 
   CGContextRestoreGState(cgContext);
 
@@ -1855,19 +1893,17 @@ nsNativeThemeCocoa::DrawWidgetBackground
       }
 
       DrawSpinButtons(cgContext, kThemeIncDecButton, macRect, state,
                       kThemeAdornmentNone, eventState, aFrame);
     }
       break;
 
     case NS_THEME_TOOLBAR_BUTTON:
-      DrawButton(cgContext, kThemePushButton, macRect,
-                 IsDefaultButton(aFrame), kThemeButtonOn, kThemeAdornmentNone,
-                 eventState, aFrame);
+      DrawSegment(cgContext, macRect, eventState, aFrame, toolbarButtonRenderSettings);
       break;
 
     case NS_THEME_TOOLBAR_SEPARATOR: {
       HIThemeSeparatorDrawInfo sdi = { 0, kThemeStateActive };
       HIThemeDrawSeparator(&macRect, &sdi, cgContext, HITHEME_ORIENTATION);
     }
       break;
 
@@ -2104,17 +2140,17 @@ nsNativeThemeCocoa::DrawWidgetBackground
       CGContextSetRGBFillColor(cgContext, 0.745, 0.745, 0.745, 1.0);
       CGContextFillRect(cgContext, CGRectMake(x, y + 1, 1, h - 1));
       CGContextFillRect(cgContext, CGRectMake(x + w - 1, y + 1, 1, h - 1));
       CGContextFillRect(cgContext, CGRectMake(x + 1, y + h - 1, w - 2, 1));
     }
       break;
     
     case NS_THEME_TAB:
-      DrawTab(cgContext, macRect, eventState, aFrame);
+      DrawSegment(cgContext, macRect, eventState, aFrame, tabRenderSettings);
       break;
 
     case NS_THEME_TAB_PANELS:
       DrawTabPanel(cgContext, macRect, aFrame);
       break;
 
     case NS_THEME_RESIZER:
       DrawResizer(cgContext, macRect, aFrame);
@@ -2157,16 +2193,22 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDe
       if (IsButtonTypeMenu(aFrame)) {
         *aResult = RTLAwareMargin(kAquaDropdownBorder, aFrame);
       } else {
         aResult->SizeTo(7, 1, 7, 3);
       }
       break;
     }
 
+    case NS_THEME_TOOLBAR_BUTTON:
+    {
+      aResult->SizeTo(4, 1, 4, 1);
+      break;
+    }
+
     case NS_THEME_CHECKBOX:
     case NS_THEME_RADIO:
     {
       // nsFormControlFrame::GetIntrinsicWidth and nsFormControlFrame::GetIntrinsicHeight
       // assume a border width of 2px.
       aResult->SizeTo(2, 2, 2, 2);
       break;
     }
@@ -2273,16 +2315,17 @@ nsNativeThemeCocoa::GetWidgetPadding(nsD
 }
 
 PRBool
 nsNativeThemeCocoa::GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
                                       PRUint8 aWidgetType, nsRect* aOverflowRect)
 {
   switch (aWidgetType) {
     case NS_THEME_BUTTON:
+    case NS_THEME_TOOLBAR_BUTTON:
     case NS_THEME_TEXTFIELD:
     case NS_THEME_TEXTFIELD_MULTILINE:
     case NS_THEME_SEARCHFIELD:
     case NS_THEME_LISTBOX:
     case NS_THEME_DROPDOWN:
     case NS_THEME_DROPDOWN_BUTTON:
     case NS_THEME_DROPDOWN_TEXTFIELD:
     case NS_THEME_CHECKBOX:
@@ -2323,16 +2366,22 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
   switch (aWidgetType) {
     case NS_THEME_BUTTON:
     {
       aResult->SizeTo(pushButtonSettings.minimumSizes[miniControlSize].width,
                       pushButtonSettings.naturalSizes[miniControlSize].height);
       break;
     }
 
+    case NS_THEME_TOOLBAR_BUTTON:
+    {
+      aResult->SizeTo(0, toolbarButtonHeights[miniControlSize]);
+      break;
+    }
+
     case NS_THEME_SPINNER:
     {
       SInt32 buttonHeight = 0, buttonWidth = 0;
       ::GetThemeMetric(kThemeMetricLittleArrowsWidth, &buttonWidth);
       ::GetThemeMetric(kThemeMetricLittleArrowsHeight, &buttonHeight);
       aResult->SizeTo(buttonWidth, buttonHeight);
       *aIsOverridable = PR_FALSE;
       break;
@@ -2383,17 +2432,17 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
       SInt32 headerHeight = 0;
       ::GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
       aResult->SizeTo(0, headerHeight - 1); // We don't need the top border.
       break;
     }
 
     case NS_THEME_TAB:
     {
-      aResult->SizeTo(0, NATURAL_MINI_TAB_BUTTON_HEIGHT);
+      aResult->SizeTo(0, tabHeights[miniControlSize]);
       break;
     }
 
     case NS_THEME_SCALE_HORIZONTAL:
     {
       SInt32 scaleHeight = 0;
       ::GetThemeMetric(kThemeMetricHSliderHeight, &scaleHeight);
       aResult->SizeTo(scaleHeight, scaleHeight);
@@ -2506,17 +2555,16 @@ NS_IMETHODIMP
 nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType, 
                                      nsIAtom* aAttribute, PRBool* aShouldRepaint)
 {
   // Some widget types just never change state.
   switch (aWidgetType) {
     case NS_THEME_TOOLBOX:
     case NS_THEME_TOOLBAR:
     case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
-    case NS_THEME_TOOLBAR_BUTTON:
     case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 
     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
     case NS_THEME_STATUSBAR:
     case NS_THEME_STATUSBAR_PANEL:
     case NS_THEME_STATUSBAR_RESIZER_PANEL:
     case NS_THEME_TOOLTIP:
     case NS_THEME_TAB_PANELS:
     case NS_THEME_TAB_PANEL:
@@ -2592,16 +2640,17 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
     
     case NS_THEME_CHECKBOX:
     case NS_THEME_CHECKBOX_CONTAINER:
     case NS_THEME_RADIO:
     case NS_THEME_RADIO_CONTAINER:
     case NS_THEME_GROUPBOX:
     case NS_THEME_BUTTON:
     case NS_THEME_BUTTON_BEVEL:
+    case NS_THEME_TOOLBAR_BUTTON:
     case NS_THEME_SPINNER:
     case NS_THEME_TOOLBAR:
     case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
     case NS_THEME_STATUSBAR:
     case NS_THEME_TEXTFIELD:
     case NS_THEME_TEXTFIELD_MULTILINE:
     case NS_THEME_SEARCHFIELD:
     //case NS_THEME_TOOLBOX:
--- a/widget/src/xpwidgets/nsNativeTheme.cpp
+++ b/widget/src/xpwidgets/nsNativeTheme.cpp
@@ -203,16 +203,28 @@ nsNativeTheme::IsButtonTypeMenu(nsIFrame
     return PR_FALSE;
 
   nsIContent* content = aFrame->GetContent();
   return content->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::type,
                               NS_LITERAL_STRING("menu"), eCaseMatters);
 }
 
 PRBool
+nsNativeTheme::IsPressedButton(nsIFrame* aFrame)
+{
+  nsEventStates eventState = GetContentState(aFrame, NS_THEME_TOOLBAR_BUTTON);
+  if (IsDisabled(aFrame, eventState))
+    return PR_FALSE;
+
+  return IsOpenButton(aFrame) ||
+         eventState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER);
+}
+
+
+PRBool
 nsNativeTheme::GetIndeterminate(nsIFrame* aFrame)
 {
   if (!aFrame)
     return PR_FALSE;
 
   nsIContent* content = aFrame->GetContent();
 
   if (content->IsXUL()) {
@@ -405,67 +417,26 @@ nsNativeTheme::IsFirstTab(nsIFrame* aFra
     if (first->GetRect().width > 0 && first->GetContent()->Tag() == nsWidgetAtoms::tab)
       return (first == aFrame);
     first = first->GetNextSibling();
   }
   return PR_FALSE;
 }
 
 PRBool
-nsNativeTheme::IsLastTab(nsIFrame* aFrame)
-{
-  if (!aFrame)
-    return PR_FALSE;
-
-  while ((aFrame = aFrame->GetNextSibling())) {
-    if (aFrame->GetRect().width > 0 && aFrame->GetContent()->Tag() == nsWidgetAtoms::tab)
-      return PR_FALSE;
-  }
-  return PR_TRUE;
-}
-
-PRBool
 nsNativeTheme::IsHorizontal(nsIFrame* aFrame)
 {
   if (!aFrame)
     return PR_FALSE;
     
   return !aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::orient,
                                             nsWidgetAtoms::vertical, 
                                             eCaseMatters);
 }
 
-PRBool
-nsNativeTheme::IsNextToSelectedTab(nsIFrame* aFrame, PRInt32 aOffset)
-{
-  if (!aFrame)
-    return PR_FALSE;
-
-  if (aOffset == 0)
-    return IsSelectedTab(aFrame);
-
-  PRInt32 thisTabIndex = -1, selectedTabIndex = -1;
-
-  nsIFrame* currentTab = aFrame->GetParent()->GetFirstChild(NULL);
-  for (PRInt32 i = 0; currentTab; currentTab = currentTab->GetNextSibling()) {
-    if (currentTab->GetRect().width == 0)
-      continue;
-    if (aFrame == currentTab)
-      thisTabIndex = i;
-    if (IsSelectedTab(currentTab))
-      selectedTabIndex = i;
-    ++i;
-  }
-
-  if (thisTabIndex == -1 || selectedTabIndex == -1)
-    return PR_FALSE;
-
-  return (thisTabIndex - selectedTabIndex == aOffset);
-}
-
 // progressbar:
 PRBool
 nsNativeTheme::IsIndeterminateProgress(nsIFrame* aFrame,
                                        nsEventStates aEventStates)
 {
   if (!aFrame || !aFrame->GetContent())
     return PR_FALSE;
 
@@ -584,8 +555,30 @@ nsNativeTheme::Notify(nsITimer* aTimer)
       frame->InvalidateOverflowRect();
     }
   }
 
   mAnimatedContentList.Clear();
   mAnimatedContentTimeout = PR_UINT32_MAX;
   return NS_OK;
 }
+
+nsIFrame*
+nsNativeTheme::GetAdjacentSiblingFrameWithSameAppearance(nsIFrame* aFrame,
+                                                         PRBool aNextSibling)
+{
+  if (!aFrame)
+    return nsnull;
+
+  // Find the next visible sibling.
+  nsIFrame* sibling = aFrame;
+  do {
+    sibling = aNextSibling ? sibling->GetNextSibling() : sibling->GetPrevSibling();
+  } while (sibling && sibling->GetRect().width == 0);
+
+  // Check same appearance and adjacency.
+  if (!sibling ||
+      sibling->GetStyleDisplay()->mAppearance != aFrame->GetStyleDisplay()->mAppearance ||
+      (sibling->GetRect().XMost() != aFrame->GetRect().x &&
+       aFrame->GetRect().XMost() != sibling->GetRect().x))
+    return nsnull;
+  return sibling;
+}
--- a/widget/src/xpwidgets/nsNativeTheme.h
+++ b/widget/src/xpwidgets/nsNativeTheme.h
@@ -117,51 +117,39 @@ class nsNativeTheme : public nsITimerCal
   // scrollbar button:
   PRInt32 GetScrollbarButtonType(nsIFrame* aFrame);
 
   // tab:
   PRBool IsSelectedTab(nsIFrame* aFrame) {
     return CheckBooleanAttr(aFrame, nsWidgetAtoms::selected);
   }
   
-  PRBool IsNextToSelectedTab(nsIFrame* aFrame, PRInt32 aOffset);
-  
-  PRBool IsBeforeSelectedTab(nsIFrame* aFrame) {
-    return IsNextToSelectedTab(aFrame, -1);
-  }
-  
-  PRBool IsAfterSelectedTab(nsIFrame* aFrame) {
-    return IsNextToSelectedTab(aFrame, 1);
-  }
-
-  PRBool IsLeftToSelectedTab(nsIFrame* aFrame) {
-    return IsFrameRTL(aFrame) ? IsAfterSelectedTab(aFrame) : IsBeforeSelectedTab(aFrame);
-  }
-
-  PRBool IsRightToSelectedTab(nsIFrame* aFrame) {
-    return IsFrameRTL(aFrame) ? IsBeforeSelectedTab(aFrame) : IsAfterSelectedTab(aFrame);
-  }
-
   // button / toolbarbutton:
   PRBool IsCheckedButton(nsIFrame* aFrame) {
     return CheckBooleanAttr(aFrame, nsWidgetAtoms::checked);
   }
 
+  PRBool IsSelectedButton(nsIFrame* aFrame) {
+    return CheckBooleanAttr(aFrame, nsWidgetAtoms::checked) ||
+           CheckBooleanAttr(aFrame, nsWidgetAtoms::selected);
+  }
+
   PRBool IsOpenButton(nsIFrame* aFrame) {
     return CheckBooleanAttr(aFrame, nsWidgetAtoms::open);
   }
 
+  PRBool IsPressedButton(nsIFrame* aFrame);
+
   // treeheadercell:
   TreeSortDirection GetTreeSortDirection(nsIFrame* aFrame);
   PRBool IsLastTreeHeaderCell(nsIFrame* aFrame);
 
   // tab:
   PRBool IsBottomTab(nsIFrame* aFrame);
   PRBool IsFirstTab(nsIFrame* aFrame);
-  PRBool IsLastTab(nsIFrame* aFrame);
   
   PRBool IsHorizontal(nsIFrame* aFrame);
 
   // progressbar:
   PRBool IsIndeterminateProgress(nsIFrame* aFrame, nsEventStates aEventStates);
   PRBool IsVerticalProgress(nsIFrame* aFrame);
 
   // textfield:
@@ -182,13 +170,16 @@ class nsNativeTheme : public nsITimerCal
   PRBool CheckBooleanAttr(nsIFrame* aFrame, nsIAtom* aAtom);
 
   PRBool GetCheckedOrSelected(nsIFrame* aFrame, PRBool aCheckSelected);
   PRBool GetIndeterminate(nsIFrame* aFrame);
 
   PRBool QueueAnimatedContentForRefresh(nsIContent* aContent,
                                         PRUint32 aMinimumFrameRate);
 
+  nsIFrame* GetAdjacentSiblingFrameWithSameAppearance(nsIFrame* aFrame,
+                                                      PRBool aNextSibling);
+
  private:
   PRUint32 mAnimatedContentTimeout;
   nsCOMPtr<nsITimer> mAnimatedContentTimer;
   nsAutoTArray<nsCOMPtr<nsIContent>, 20> mAnimatedContentList;
 };