Bug 516924 - Don't pass our ChildViews to drawWithFrame:inView: when drawing NSCells (e.g. buttons) because that causes Cocoa to think our views have focus rings, so it starts repainting unnecessarily when we invalidate rects near the view boundaries. r=josh

This commit is contained in:
Markus Stange 2009-09-17 10:06:16 +12:00
parent 6edbc5a226
commit 8eea03961f
3 changed files with 41 additions and 34 deletions

View File

@ -2332,6 +2332,8 @@ NSEvent* gLastDragEvent = nil;
mGestureState = eGestureState_None; mGestureState = eGestureState_None;
mCumulativeMagnification = 0.0; mCumulativeMagnification = 0.0;
mCumulativeRotation = 0.0; mCumulativeRotation = 0.0;
[self setFocusRingType:NSFocusRingTypeNone];
} }
// register for things we'll take from other applications // register for things we'll take from other applications
@ -2545,21 +2547,6 @@ NSEvent* gLastDragEvent = nil;
[super viewDidMoveToWindow]; [super viewDidMoveToWindow];
} }
// 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 - (void)scrollRect:(NSRect)aRect by:(NSSize)offset
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;

View File

@ -50,6 +50,8 @@
#include "gfxASurface.h" #include "gfxASurface.h"
@class CellDrawView;
class nsNativeThemeCocoa : private nsNativeTheme, class nsNativeThemeCocoa : private nsNativeTheme,
public nsITheme public nsITheme
{ {
@ -148,6 +150,7 @@ private:
NSSearchFieldCell* mSearchFieldCell; NSSearchFieldCell* mSearchFieldCell;
NSPopUpButtonCell* mDropdownCell; NSPopUpButtonCell* mDropdownCell;
NSComboBoxCell* mComboBoxCell; NSComboBoxCell* mComboBoxCell;
CellDrawView* mCellDrawView;
}; };
#endif // nsNativeThemeCocoa_h_ #endif // nsNativeThemeCocoa_h_

View File

@ -81,6 +81,34 @@ extern "C" {
- (int)_realControlTint { return [self controlTint]; } - (int)_realControlTint { return [self controlTint]; }
@end @end
// The purpose of this class is to provide objects that can be used when drawing
// NSCells using drawWithFrame:inView: without causing any harm. The only
// messages that will be sent to such an object are "isFlipped" and
// "currentEditor": isFlipped needs to return YES in order to avoid drawing bugs
// on 10.4 (see bug 465069); currentEditor (which isn't even a method of
// NSView) will be called when drawing search fields, and we only provide it in
// order to prevent "unrecognized selector" exceptions.
// There's no need to pass the actual NSView that we're drawing into to
// drawWithFrame:inView:. What's more, doing so even causes unnecessary
// invalidations as soon as we draw a focusring!
@interface CellDrawView : NSView
@end;
@implementation CellDrawView
- (BOOL)isFlipped
{
return YES;
}
- (NSText*)currentEditor
{
return nil;
}
@end
static void DrawFocusRing(NSRect rect, float radius) static void DrawFocusRing(NSRect rect, float radius)
{ {
NSSetFocusRingStyle(NSFocusRingOnly); NSSetFocusRingStyle(NSFocusRingOnly);
@ -171,18 +199,6 @@ static void InflateControlRect(NSRect* rect, NSControlSize cocoaControlSize, con
rect->size.height += buttonMargins[bottomMargin] + buttonMargins[topMargin]; 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, static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
nsIWidget** aTopLevelWidget = NULL) nsIWidget** aTopLevelWidget = NULL)
{ {
@ -249,6 +265,8 @@ nsNativeThemeCocoa::nsNativeThemeCocoa()
[mComboBoxCell setEditable:YES]; [mComboBoxCell setEditable:YES];
[mComboBoxCell setFocusRingType:NSFocusRingTypeExterior]; [mComboBoxCell setFocusRingType:NSFocusRingTypeExterior];
mCellDrawView = [[CellDrawView alloc] init];
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
@ -262,6 +280,7 @@ nsNativeThemeCocoa::~nsNativeThemeCocoa()
[mSearchFieldCell release]; [mSearchFieldCell release];
[mDropdownCell release]; [mDropdownCell release];
[mComboBoxCell release]; [mComboBoxCell release];
[mCellDrawView release];
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
@ -621,9 +640,7 @@ nsNativeThemeCocoa::DrawCheckboxOrRadio(CGContextRef cgContext, PRBool inCheckbo
DrawCellWithSnapping(cell, cgContext, drawRect, DrawCellWithSnapping(cell, cgContext, drawRect,
inCheckbox ? checkboxSettings : radioSettings, inCheckbox ? checkboxSettings : radioSettings,
VerticalAlignFactor(aFrame), VerticalAlignFactor(aFrame), mCellDrawView, NO);
NativeViewForFrame(aFrame),
NO);
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
@ -664,7 +681,7 @@ nsNativeThemeCocoa::DrawSearchField(CGContextRef cgContext, const HIRect& inBoxR
[cell setShowsFirstResponder:IsFocused(aFrame)]; [cell setShowsFirstResponder:IsFocused(aFrame)];
DrawCellWithSnapping(cell, cgContext, inBoxRect, searchFieldSettings, DrawCellWithSnapping(cell, cgContext, inBoxRect, searchFieldSettings,
VerticalAlignFactor(aFrame), NativeViewForFrame(aFrame), VerticalAlignFactor(aFrame), mCellDrawView,
IsFrameRTL(aFrame)); IsFrameRTL(aFrame));
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
@ -720,12 +737,12 @@ nsNativeThemeCocoa::DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRe
[mPushButtonCell setBezelStyle:NSShadowlessSquareBezelStyle]; [mPushButtonCell setBezelStyle:NSShadowlessSquareBezelStyle];
DrawCellWithScaling(mPushButtonCell, cgContext, inBoxRect, NSRegularControlSize, DrawCellWithScaling(mPushButtonCell, cgContext, inBoxRect, NSRegularControlSize,
NSZeroSize, NSMakeSize(14, 0), NULL, NSZeroSize, NSMakeSize(14, 0), NULL,
NativeViewForFrame(aFrame), IsFrameRTL(aFrame)); mCellDrawView, IsFrameRTL(aFrame));
} else { } else {
[mPushButtonCell setBezelStyle:NSRoundedBezelStyle]; [mPushButtonCell setBezelStyle:NSRoundedBezelStyle];
DrawCellWithSnapping(mPushButtonCell, cgContext, inBoxRect, pushButtonSettings, DrawCellWithSnapping(mPushButtonCell, cgContext, inBoxRect, pushButtonSettings,
0.5f, NativeViewForFrame(aFrame), IsFrameRTL(aFrame), 1.0f); 0.5f, mCellDrawView, IsFrameRTL(aFrame), 1.0f);
} }
#if DRAW_IN_FRAME_DEBUG #if DRAW_IN_FRAME_DEBUG
@ -882,7 +899,7 @@ nsNativeThemeCocoa::DrawDropdown(CGContextRef cgContext, const HIRect& inBoxRect
const CellRenderSettings& settings = isEditable ? editableMenulistSettings : dropdownSettings; const CellRenderSettings& settings = isEditable ? editableMenulistSettings : dropdownSettings;
DrawCellWithSnapping(cell, cgContext, inBoxRect, settings, DrawCellWithSnapping(cell, cgContext, inBoxRect, settings,
0.5f, NativeViewForFrame(aFrame), IsFrameRTL(aFrame)); 0.5f, mCellDrawView, IsFrameRTL(aFrame));
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }