Bug 450800 - Add -moz-appearance: searchfield on Mac OS X; general NSCell drawing cleanup. r=smichaud sr=roc
authorMarkus Stange <mstange@themasta.com>
Sat, 06 Dec 2008 12:40:58 +0100
changeset 22417 22614dd65a9febf80b55728aee7b0fcc2e7d831a
parent 22416 1e8779804b503464eda87a1717a094ece8cb63fc
child 22418 02effdd7d4ad7fe67289ddb1d83bac637a8ff0f7
push idunknown
push userunknown
push dateunknown
reviewerssmichaud, roc
bugs450800
milestone1.9.2a1pre
Bug 450800 - Add -moz-appearance: searchfield on Mac OS X; general NSCell drawing cleanup. r=smichaud sr=roc
gfx/public/nsThemeConstants.h
layout/style/nsCSSKeywordList.h
layout/style/nsCSSProps.cpp
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsNativeThemeCocoa.h
widget/src/cocoa/nsNativeThemeCocoa.mm
--- a/gfx/public/nsThemeConstants.h
+++ b/gfx/public/nsThemeConstants.h
@@ -151,16 +151,19 @@
 #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 searchfield
+#define NS_THEME_SEARCHFIELD                               98
+
 // A dropdown list.
 #define NS_THEME_DROPDOWN                                  101
 
 // The dropdown button(s) that open up a dropdown list.
 #define NS_THEME_DROPDOWN_BUTTON                           102
 
 // The text part of a dropdown list, to left of button
 #define NS_THEME_DROPDOWN_TEXT                             103
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -539,16 +539,17 @@ CSS_KEY(scrollbarbutton-left, scrollbarb
 CSS_KEY(scrollbarbutton-right, scrollbarbutton_right)
 CSS_KEY(scrollbartrack-horizontal, scrollbartrack_horizontal)
 CSS_KEY(scrollbartrack-vertical, scrollbartrack_vertical)
 CSS_KEY(scrollbarthumb-horizontal, scrollbarthumb_horizontal)
 CSS_KEY(scrollbarthumb-vertical, scrollbarthumb_vertical)
 CSS_KEY(textfield, textfield)
 CSS_KEY(textfield-multiline, textfield_multiline)
 CSS_KEY(caret, caret)
+CSS_KEY(searchfield, searchfield)
 CSS_KEY(menubar, menubar)
 CSS_KEY(menupopup, menupopup)
 CSS_KEY(menuitem, menuitem)
 CSS_KEY(checkmenuitem, checkmenuitem)
 CSS_KEY(radiomenuitem, radiomenuitem)
 CSS_KEY(menucheckbox, menucheckbox)
 CSS_KEY(menuradio, menuradio)
 CSS_KEY(menuseparator, menuseparator)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -286,16 +286,17 @@ const PRInt32 nsCSSProps::kAppearanceKTa
   eCSSKeyword_scrollbarbutton_right,  NS_THEME_SCROLLBAR_BUTTON_RIGHT,
   eCSSKeyword_scrollbartrack_horizontal,    NS_THEME_SCROLLBAR_TRACK_HORIZONTAL,
   eCSSKeyword_scrollbartrack_vertical,      NS_THEME_SCROLLBAR_TRACK_VERTICAL,
   eCSSKeyword_scrollbarthumb_horizontal,    NS_THEME_SCROLLBAR_THUMB_HORIZONTAL,
   eCSSKeyword_scrollbarthumb_vertical,      NS_THEME_SCROLLBAR_THUMB_VERTICAL,
   eCSSKeyword_textfield,              NS_THEME_TEXTFIELD,
   eCSSKeyword_textfield_multiline,    NS_THEME_TEXTFIELD_MULTILINE,
   eCSSKeyword_caret,                  NS_THEME_TEXTFIELD_CARET,
+  eCSSKeyword_searchfield,            NS_THEME_SEARCHFIELD,
   eCSSKeyword_menulist,               NS_THEME_DROPDOWN,
   eCSSKeyword_menulistbutton,         NS_THEME_DROPDOWN_BUTTON,
   eCSSKeyword_menulisttext,           NS_THEME_DROPDOWN_TEXT,
   eCSSKeyword_menulisttextfield,      NS_THEME_DROPDOWN_TEXTFIELD,
   eCSSKeyword_scale_horizontal,       NS_THEME_SCALE_HORIZONTAL,
   eCSSKeyword_scale_vertical,         NS_THEME_SCALE_VERTICAL,
   eCSSKeyword_scalethumb_horizontal,  NS_THEME_SCALE_THUMB_HORIZONTAL,
   eCSSKeyword_scalethumb_vertical,    NS_THEME_SCALE_THUMB_VERTICAL,
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -2868,16 +2868,32 @@ NSEvent* gLastDragEvent = nil;
     mGeckoChild->LiveResizeEnded();
 
   [super viewDidEndLiveResize];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 
+// Needed to deal with the consequences of calling [NSCell
+// drawWithFrame:inView:] with a ChildView object as the inView parameter
+// (this can happen in nsNativeThemeCocoa.mm):  drawWithFrame:inView:
+// expects an NSControl as its inView parameter, and may call [NSControl
+// currentEditor] on it.  But since a ChildView object (like an NSView object)
+// isn't a control, it doesn't have a "current editor", or a currentEditor
+// method.  So calling currentEditor on it will trigger a Objective-C
+// "unrecognized selector" exception.  To prevent this, ChildView needs its
+// own currentEditor method.  Since a ChildView object never has a "current
+// editor", it should always return nil.
+- (NSText*)currentEditor
+{
+  return nil;
+}
+
+
 - (void)scrollRect:(NSRect)aRect by:(NSSize)offset
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   // Update any pending dirty rects to reflect the new scroll position
   if (mPendingDirtyRects) {
     unsigned int count = [mPendingDirtyRects count];
     for (unsigned int i = 0; i < count; ++i) {
--- a/widget/src/cocoa/nsNativeThemeCocoa.h
+++ b/widget/src/cocoa/nsNativeThemeCocoa.h
@@ -108,16 +108,17 @@ protected:
                  PRBool inIsDisabled, PRInt32 inState,
                  PRBool inDirection, PRBool inIsReverse,
                  PRInt32 inCurrentValue,
                  PRInt32 inMinValue, PRInt32 inMaxValue,
                  nsIFrame* aFrame);
   void DrawCheckboxOrRadio(CGContextRef cgContext, PRBool inCheckbox,
                            const HIRect& inBoxRect, PRBool inSelected,
                            PRBool inDisabled, PRInt32 inState, nsIFrame* aFrame);
+  void DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect, nsIFrame* aFrame);
   void DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect, PRBool inIsDefault,
                       PRBool inDisabled, PRInt32 inState, nsIFrame* aFrame);
   void DrawButton(CGContextRef context, ThemeButtonKind inKind,
                   const HIRect& inBoxRect, PRBool inIsDefault, 
                   PRBool inDisabled, ThemeButtonValue inValue,
                   ThemeButtonAdornment inAdornment, PRInt32 inState, nsIFrame* aFrame);
   void DrawSpinButtons(CGContextRef context, ThemeButtonKind inKind,
                        const HIRect& inBoxRect,
@@ -133,11 +134,12 @@ protected:
   void GetScrollbarDrawInfo (HIThemeTrackDrawInfo& aTdi, nsIFrame *aFrame, 
                              const HIRect& aRect, PRBool aShouldGetButtonStates);
   nsIFrame* GetParentScrollbarFrame(nsIFrame *aFrame);
 
 private:
   NSButtonCell* mPushButtonCell;
   NSButtonCell* mRadioButtonCell;
   NSButtonCell* mCheckboxCell;
+  NSSearchFieldCell* mSearchFieldCell;
 };
 
 #endif // nsNativeThemeCocoa_h_
--- a/widget/src/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/src/cocoa/nsNativeThemeCocoa.mm
@@ -76,16 +76,40 @@ extern "C" {
 // Workaround for NSCell control tint drawing
 // Without this workaround, NSCells are always drawn with the clear control tint
 // as long as they're not attached to an NSControl which is a subview of an active window.
 // XXXmstange Why doesn't Webkit need this?
 @implementation NSCell (ControlTintWorkaround)
 - (int)_realControlTint { return [self controlTint]; }
 @end
 
+// On 10.4, NSSearchFieldCells can't draw focus rings.
+@interface SearchFieldCellWithFocusRing : NSSearchFieldCell {} @end
+
+@implementation SearchFieldCellWithFocusRing
+
+- (void) drawWithFrame:(NSRect)rect inView:(NSView*)controlView
+{
+  [super drawWithFrame:rect inView:controlView];
+  if (!nsToolkit::OnLeopardOrLater() && [self showsFirstResponder]) {
+    NSSetFocusRingStyle(NSFocusRingOnly);
+    NSBezierPath* path = [NSBezierPath bezierPath];
+    float radius = NSHeight(rect) / 2;
+    rect = NSInsetRect(rect, radius, radius);
+    [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0];
+    [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0];
+    [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMaxY(rect)) radius:radius startAngle:  0.0 endAngle: 90.0];
+    [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMaxY(rect)) radius:radius startAngle: 90.0 endAngle:180.0];
+    [path closePath];
+    [path fill];
+  }
+}
+
+@end
+
 // Copied from nsLookAndFeel.h
 // Apple hasn't defined a constant for scollbars with two arrows on each end, so we'll use this one.
 static const int kThemeScrollBarArrowsBoth = 2;
 
 #define HITHEME_ORIENTATION kHIThemeOrientationNormal
 #define MAX_FOCUS_RING_WIDTH 4
 
 // These enums are for indexing into the margin array.
@@ -124,16 +148,28 @@ static void InflateControlRect(NSRect* r
   int controlSize = EnumSizeForCocoaSize(cocoaControlSize);
   const float* buttonMargins = marginSet[osIndex][controlSize];
   rect->origin.x -= buttonMargins[leftMargin];
   rect->origin.y -= buttonMargins[bottomMargin];
   rect->size.width += buttonMargins[leftMargin] + buttonMargins[rightMargin];
   rect->size.height += buttonMargins[bottomMargin] + buttonMargins[topMargin];
 }
 
+static NSView* NativeViewForFrame(nsIFrame* aFrame)
+{
+  if (!aFrame)
+    return nil;  
+
+  nsIWidget* widget = aFrame->GetWindow();
+  if (!widget)
+    return nil;
+
+  return (NSView*)widget->GetNativeData(NS_NATIVE_WIDGET);
+}
+
 static NSWindow* NativeWindowForFrame(nsIFrame* aFrame, int* aLevelsUp = NULL,
                                       nsIWidget** aTopLevelWidget = NULL)
 {
   if (!aFrame)
     return nil;  
 
   nsIWidget* widget = aFrame->GetWindow();
   if (!widget)
@@ -176,26 +212,33 @@ nsNativeThemeCocoa::nsNativeThemeCocoa()
   [mPushButtonCell setHighlightsBy:NSPushInCellMask];
 
   mRadioButtonCell = [[NSButtonCell alloc] initTextCell:nil];
   [mRadioButtonCell setButtonType:NSRadioButton];
 
   mCheckboxCell = [[NSButtonCell alloc] initTextCell:nil];
   [mCheckboxCell setButtonType:NSSwitchButton];
 
+  mSearchFieldCell = [[SearchFieldCellWithFocusRing alloc] initTextCell:@""];
+  [mSearchFieldCell setBezelStyle:NSTextFieldRoundedBezel];
+  [mSearchFieldCell setBezeled:YES];
+  [mSearchFieldCell setEditable:YES];
+  [mSearchFieldCell setFocusRingType:NSFocusRingTypeExterior];
+
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 nsNativeThemeCocoa::~nsNativeThemeCocoa()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [mPushButtonCell release];
   [mRadioButtonCell release];
   [mCheckboxCell release];
+  [mSearchFieldCell release];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 // Limit on the area of the target rect (in pixels^2) in
 // DrawCellWithScaling(), DrawButton() and DrawScrollbar(), above which we
 // don't draw the object into a bitmap buffer.  This is to avoid crashes in
 // [NSGraphicsContext graphicsContextWithGraphicsPort:flipped:] and
@@ -222,29 +265,28 @@ nsNativeThemeCocoa::~nsNativeThemeCocoa(
  *  a scale will be applied to the context so that the minimum is used
  *  for drawing.  If a control has no minimum dimensions in either/both
  *  axes, pass 0.0f.
  * marginSet - an array of margins; a multidimensional array of [2][3][4],
  *  with the first dimension being the OS version (Tiger or Leopard),
  *  the second being the control size (mini, small, regular), and the third
  *  being the 4 margin values (left, top, right, bottom).
  * flip - Whether to draw the control mirrored
- * needsBuffer - Set this to false if no buffer should be used. Bypassing the
- *  buffer is faster but it can lead to painting problems with accumulating
- *  focus rings.
+ * view - The NSView that we're drawing into. As far as I can tell, it doesn't
+ *  matter if this is really the right view; it just has to return YES when
+ *  asked for isFlipped. Otherwise we'll get drawing bugs on 10.4.
  */
 static void DrawCellWithScaling(NSCell *cell,
                                 CGContextRef cgContext,
                                 const HIRect& destRect,
                                 NSControlSize controlSize,
                                 NSSize naturalSize,
                                 NSSize minimumSize,
                                 const float marginSet[][3][4],
-                                PRBool flip,
-                                PRBool needsBuffer = PR_TRUE)
+                                NSView* view)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   NSRect drawRect = NSMakeRect(destRect.origin.x, destRect.origin.y, destRect.size.width, destRect.size.height);
 
   if (naturalSize.width != 0.0f)
     drawRect.size.width = naturalSize.width;
   if (naturalSize.height != 0.0f)
@@ -259,72 +301,60 @@ static void DrawCellWithScaling(NSCell *
   // Honor minimum sizes.
   if (drawRect.size.width < minimumSize.width)
     drawRect.size.width = minimumSize.width;
   if (drawRect.size.height < minimumSize.height)
     drawRect.size.height = minimumSize.height;
 
   [NSGraphicsContext saveGraphicsState];
 
-  if (flip) {
-    // This flips the image in place and is necessary to work around a bug in the way
-    // NSButtonCell draws buttons.
-    CGContextScaleCTM(cgContext, 1.0f, -1.0f);
-    CGContextTranslateCTM(cgContext, 0.0f, -(2.0 * destRect.origin.y + destRect.size.height));
-  }
-
-  // Fall back to no bitmap buffer (and no scaling) if the area of our cell
-  // (in pixels^2) is too large.
-  BOOL noBufferOverride = (drawRect.size.width * drawRect.size.height > BITMAP_MAX_AREA);
-
-  if ((!needsBuffer && drawRect.size.width == destRect.size.width &&
-       drawRect.size.height == destRect.size.height) || noBufferOverride) {
+  // Only skip the buffer if the area of our cell (in pixels^2) is too large.
+  if (drawRect.size.width * drawRect.size.height > BITMAP_MAX_AREA) {
     // Inflate the rect Gecko gave us by the margin for the control.
     InflateControlRect(&drawRect, controlSize, marginSet);
 
     NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
-
-    // Set up the graphics context we've been asked to draw to.
     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]];
 
-    // [NSView focusView] may return nil here, but
-    // [NSCell drawWithFrame:inView:] can deal with that.
-    [cell drawWithFrame:drawRect inView:[NSView focusView]];
+    [cell drawWithFrame:drawRect inView:view];
 
     [NSGraphicsContext setCurrentContext:savedContext];
   }
   else {
     float w = ceil(drawRect.size.width);
     float h = ceil(drawRect.size.height);
-
-    NSRect tmpRect = NSMakeRect(0.0f, 0.0f, w, h);
+    NSRect tmpRect = NSMakeRect(MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH, w, h);
 
     // inflate to figure out the frame we need to tell NSCell to draw in, to get something that's 0,0,w,h
     InflateControlRect(&tmpRect, controlSize, marginSet);
 
     // and then, expand by MAX_FOCUS_RING_WIDTH size to make sure we can capture any focus ring
     w += MAX_FOCUS_RING_WIDTH * 2.0;
     h += MAX_FOCUS_RING_WIDTH * 2.0;
 
     CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
     CGContextRef ctx = CGBitmapContextCreate(NULL,
                                              (int) w, (int) h,
                                              8, (int) w * 4,
                                              rgb, kCGImageAlphaPremultipliedFirst);
     CGColorSpaceRelease(rgb);
 
-    CGContextTranslateCTM(ctx, MAX_FOCUS_RING_WIDTH, MAX_FOCUS_RING_WIDTH);
+    // We need to flip the image twice in order to avoid drawing bugs on 10.4, see bug 465069.
+    // This is the first flip transform, applied to cgContext.
+    CGContextScaleCTM(cgContext, 1.0f, -1.0f);
+    CGContextTranslateCTM(cgContext, 0.0f, -(2.0 * destRect.origin.y + destRect.size.height));
 
     NSGraphicsContext* savedContext = [NSGraphicsContext currentContext];
-
     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];
 
-    // [NSView focusView] may return nil here, but
-    // [NSCell drawWithFrame:inView:] can deal with that.
-    [cell drawWithFrame:tmpRect inView:[NSView focusView]];
+    // This is the second flip transform, applied to ctx.
+    CGContextScaleCTM(ctx, 1.0f, -1.0f);
+    CGContextTranslateCTM(ctx, 0.0f, -(2.0 * tmpRect.origin.y + tmpRect.size.height));
+
+    [cell drawWithFrame:tmpRect inView:view];
 
     [NSGraphicsContext setCurrentContext:savedContext];
 
     CGImageRef img = CGBitmapContextCreateImage(ctx);
 
     // Drop the image into the original destination rectangle, scaling to fit
     // Only scale MAX_FOCUS_RING_WIDTH by xscale/yscale when the resulting rect
     // doesn't extend beyond the overflow rect
@@ -378,19 +408,18 @@ struct CellRenderSettings {
  * it snaps to the next smaller control size without scaling because unscaled
  * controls look nicer.
  */
 static const float sSnapTolerance = 1.0f;
 static void DrawCellWithSnapping(NSCell *cell,
                                  CGContextRef cgContext,
                                  const HIRect& destRect,
                                  const CellRenderSettings settings,
-                                 PRBool flip,
                                  float verticalAlignFactor,
-                                 PRBool needsBuffer = PR_TRUE)
+                                 NSView* view)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   const float rectWidth = destRect.size.width, rectHeight = destRect.size.height;
   const NSSize *sizes = settings.naturalSizes;
   const NSSize miniSize = sizes[EnumSizeForCocoaSize(NSMiniControlSize)];
   const NSSize smallSize = sizes[EnumSizeForCocoaSize(NSSmallControlSize)];
   const NSSize regularSize = sizes[EnumSizeForCocoaSize(NSRegularControlSize)];
@@ -411,18 +440,19 @@ static void DrawCellWithSnapping(NSCell 
   NSControlSize controlSize = NSRegularControlSize;
   int sizeIndex = 0;
 
   // At some sizes, don't scale but snap.
   const NSControlSize smallerControlSize =
     EnumSizeForCocoaSize(controlSizeX) < EnumSizeForCocoaSize(controlSizeY) ?
     controlSizeX : controlSizeY;
   const int smallerControlSizeIndex = EnumSizeForCocoaSize(smallerControlSize);
-  float diffWidth = rectWidth - sizes[smallerControlSizeIndex].width;
-  float diffHeight = rectHeight - sizes[smallerControlSizeIndex].height;
+  const NSSize size = sizes[smallerControlSizeIndex];
+  float diffWidth = size.width ? rectWidth - size.width : 0.0f;
+  float diffHeight = size.height ? rectHeight - size.height : 0.0f;
   if (diffWidth >= 0.0f && diffHeight >= 0.0f &&
       diffWidth <= sSnapTolerance && diffHeight <= sSnapTolerance) {
     // Snap to the smaller control size.
     controlSize = smallerControlSize;
     sizeIndex = smallerControlSizeIndex;
     // Resize and center the drawRect.
     if (sizes[sizeIndex].width) {
       drawRect.origin.x += ceil((destRect.size.width - sizes[sizeIndex].width) / 2);
@@ -438,17 +468,17 @@ static void DrawCellWithSnapping(NSCell 
                   controlSizeX : controlSizeY;
     sizeIndex = EnumSizeForCocoaSize(controlSize);
    }
 
   [cell setControlSize:controlSize];
 
   NSSize minimumSize = settings.minimumSizes ? settings.minimumSizes[sizeIndex] : NSZeroSize;
   DrawCellWithScaling(cell, cgContext, drawRect, controlSize, sizes[sizeIndex],
-                      minimumSize, settings.margins, flip, needsBuffer);
+                      minimumSize, settings.margins, view);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 static float VerticalAlignFactor(nsIFrame *aFrame)
 {
   if (!aFrame)
     return 0.5f; // default: center
@@ -541,18 +571,59 @@ nsNativeThemeCocoa::DrawCheckboxOrRadio(
   [cell setEnabled:!inDisabled];
   [cell setShowsFirstResponder:(inState & NS_EVENT_STATE_FOCUS)];
   [cell setState:(inSelected ? NSOnState : NSOffState)];
   [cell setHighlighted:((inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER))];
   [cell setControlTint:(FrameIsInActiveWindow(aFrame) ? [NSColor currentControlTint] : NSClearControlTint)];
  
   DrawCellWithSnapping(cell, cgContext, inBoxRect,
                        inCheckbox ? checkboxSettings : radioSettings,
-                       nsToolkit::OnLeopardOrLater(),  // Tiger doesn't need flipping
-                       VerticalAlignFactor(aFrame));
+                       VerticalAlignFactor(aFrame),
+                       NativeViewForFrame(aFrame));
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+static const CellRenderSettings searchFieldSettings = {
+  {
+    NSMakeSize(0, 16), // mini
+    NSMakeSize(0, 19), // small
+    NSMakeSize(0, 22)  // regular
+  },
+  {
+    NSMakeSize(32, 0), // mini
+    NSMakeSize(38, 0), // small
+    NSMakeSize(44, 0)  // regular
+  },
+  {
+    { // Tiger
+      {0, 0, 0, 0},     // mini
+      {0, 0, 0, 0},     // small
+      {0, 0, 0, 0}      // regular
+    },
+    { // Leopard
+      {0, 0, 0, 0},     // mini
+      {0, 0, 0, 0},     // small
+      {0, 0, 0, 0}      // regular
+    }
+  }
+};
+
+void
+nsNativeThemeCocoa::DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
+                                    nsIFrame* aFrame)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  NSSearchFieldCell* cell = mSearchFieldCell;
+  [cell setEnabled:!IsDisabled(aFrame)];
+  [cell setShowsFirstResponder:IsFocused(aFrame)];
+
+  DrawCellWithSnapping(cell, cgContext, inBoxRect, searchFieldSettings,
+                       VerticalAlignFactor(aFrame), NativeViewForFrame(aFrame));
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 
 // These are the sizes that Gecko needs to request to draw if it wants
 // to get a standard-sized Aqua rounded bevel button drawn. Note that
 // the rects that draw these are actually a little bigger.
@@ -600,17 +671,17 @@ nsNativeThemeCocoa::DrawPushButton(CGCon
                                    isActive)];
   [mPushButtonCell setShowsFirstResponder:(inState & NS_EVENT_STATE_FOCUS) && !inDisabled && isActive];
 
   // If the button is tall enough, draw the square button style so that buttons with
   // non-standard content look good. Otherwise draw normal rounded aqua buttons.
   if (drawRect.size.height > DO_SQUARE_BUTTON_HEIGHT) {
     [mPushButtonCell setBezelStyle:NSShadowlessSquareBezelStyle];
     DrawCellWithScaling(mPushButtonCell, cgContext, inBoxRect, NSRegularControlSize,
-                        NSZeroSize, NSMakeSize(14, 0), NULL, PR_TRUE);
+                        NSZeroSize, NSMakeSize(14, 0), NULL, NativeViewForFrame(aFrame));
   } else {
     [mPushButtonCell setBezelStyle:NSRoundedBezelStyle];
 
     // Figure out what size cell control we're going to draw and grab its
     // natural height and min width.
     NSControlSize controlSize = NSRegularControlSize;
     float naturalHeight = NATURAL_REGULAR_ROUNDED_BUTTON_HEIGHT;
     float minWidth = NATURAL_REGULAR_ROUNDED_BUTTON_MIN_WIDTH;
@@ -625,18 +696,18 @@ nsNativeThemeCocoa::DrawPushButton(CGCon
       controlSize = NSSmallControlSize;
       naturalHeight = NATURAL_SMALL_ROUNDED_BUTTON_HEIGHT;
       minWidth = NATURAL_SMALL_ROUNDED_BUTTON_MIN_WIDTH;
     }
     [mPushButtonCell setControlSize:controlSize];
 
     DrawCellWithScaling(mPushButtonCell, cgContext, inBoxRect, controlSize,
                         NSMakeSize(0.0f, naturalHeight),
-                        NSMakeSize(minWidth, 0.0f),
-                        pushButtonMargins, PR_TRUE);
+                        NSMakeSize(minWidth, 0.0f), pushButtonMargins,
+                        NativeViewForFrame(aFrame));
   }
 
 #if DRAW_IN_FRAME_DEBUG
   CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
   CGContextFillRect(cgContext, inBoxRect);
 #endif
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
@@ -1498,16 +1569,20 @@ nsNativeThemeCocoa::DrawWidgetBackground
           IsFocused(aFrame)) {
         eventState |= NS_EVENT_STATE_FOCUS;
       }
 
       DrawFrame(cgContext, kHIThemeFrameTextFieldSquare,
                 macRect, (IsDisabled(aFrame) || IsReadOnly(aFrame)), eventState);
       break;
       
+    case NS_THEME_SEARCHFIELD:
+      DrawSearchField(cgContext, macRect, aFrame);
+      break;
+
     case NS_THEME_PROGRESSBAR:
       DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame),
                    PR_TRUE, GetProgressValue(aFrame),
                    GetProgressMaxValue(aFrame), aFrame);
       break;
 
     case NS_THEME_PROGRESSBAR_VERTICAL:
       DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame),
@@ -1708,16 +1783,20 @@ nsNativeThemeCocoa::GetWidgetBorder(nsID
       aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
       break;
     }
 
     case NS_THEME_TEXTFIELD_MULTILINE:
       aResult->SizeTo(1, 1, 1, 1);
       break;
 
+    case NS_THEME_SEARCHFIELD:
+      aResult->SizeTo(4, 2, 4, 2);
+      break;
+
     case NS_THEME_LISTBOX:
     {
       SInt32 frameOutset = 0;
       ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
       aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
       break;
     }
 
@@ -1786,16 +1865,17 @@ nsNativeThemeCocoa::GetWidgetPadding(nsI
 PRBool
 nsNativeThemeCocoa::GetWidgetOverflow(nsIDeviceContext* aContext, nsIFrame* aFrame,
                                       PRUint8 aWidgetType, nsRect* aOverflowRect)
 {
   switch (aWidgetType) {
     case NS_THEME_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_CHECKBOX:
     case NS_THEME_RADIO:
     case NS_THEME_TAB:
     {
       // We assume that the above widgets can draw a focus ring that will be less than
@@ -1850,16 +1930,17 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
       SInt32 popupHeight = 0;
       ::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
       aResult->SizeTo(0, popupHeight);
       break;
     }
  
     case NS_THEME_TEXTFIELD:
     case NS_THEME_TEXTFIELD_MULTILINE:
+    case NS_THEME_SEARCHFIELD:
     {
       // at minimum, we should be tall enough for 9pt text.
       // I'm using hardcoded values here because the appearance manager
       // values for the frame size are incorrect.
       aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */);
       break;
     }
       
@@ -2121,16 +2202,17 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
     case NS_THEME_BUTTON:
     case NS_THEME_BUTTON_BEVEL:
     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:
     //case NS_THEME_TOOLBAR_BUTTON:
     case NS_THEME_PROGRESSBAR:
     case NS_THEME_PROGRESSBAR_VERTICAL:
     case NS_THEME_PROGRESSBAR_CHUNK:
     case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
     case NS_THEME_TOOLBAR_SEPARATOR: