Prevent multiple redundant repaint messages from filling up the event queue leading to browser hangs under certain race conditions. b=565323 r=josh
authorBenoit Girard <b56girard@gmail.com>
Wed, 09 Jun 2010 00:11:42 -0400
changeset 43368 014ea2ea49981560a00b769205f4921c164260f8
parent 43367 ad21f6e7d15ad8e441e31d4bb22c1038c9c00d9c
child 43369 6599ff0c99816ea9a09295d20c1f1ca622ffdf54
push idunknown
push userunknown
push dateunknown
reviewersjosh
bugs565323
milestone1.9.3a5pre
Prevent multiple redundant repaint messages from filling up the event queue leading to browser hangs under certain race conditions. b=565323 r=josh
widget/src/cocoa/nsChildView.h
widget/src/cocoa/nsChildView.mm
--- a/widget/src/cocoa/nsChildView.h
+++ b/widget/src/cocoa/nsChildView.h
@@ -142,16 +142,17 @@ extern "C" long TSMProcessRawKeyEvent(Ev
   NSRange mMarkedRange;
   
   // when mouseDown: is called, we store its event here (strong)
   NSEvent* mLastMouseDownEvent;
   
   // rects that were invalidated during a draw, so have pending drawing
   NSMutableArray* mPendingDirtyRects;
   BOOL mPendingFullDisplay;
+  BOOL mPendingDisplay;
 
   // Holds our drag service across multiple drag calls. The reference to the
   // service is obtained when the mouse enters the view and is released when
   // the mouse exits or there is a drop. This prevents us from having to
   // re-establish the connection to the service manager many times per second
   // when handling |draggingUpdated:| messages.
   nsIDragService* mDragService;
 
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -2186,16 +2186,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
     mPluginEventModel = NPEventModelCarbon;
 #else
     mPluginEventModel = NPEventModelCocoa;
 #endif
     mCurKeyEvent = nil;
     mKeyDownHandled = PR_FALSE;
     mKeyPressHandled = NO;
     mKeyPressSent = NO;
+    mPendingDisplay = NO;
 
     // initialization for NSTextInput
     mMarkedRange.location = NSNotFound;
     mMarkedRange.length = 0;
 
     mLastMouseDownEvent = nil;
     mDragService = nsnull;
 
@@ -2344,48 +2345,55 @@ NSEvent* gLastDragMouseDownEvent = nil;
   mGeckoChild->DispatchWindowEvent(guiEvent);
 }
 
 - (void)setNeedsPendingDisplay
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   mPendingFullDisplay = YES;
-  [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
+  if (!mPendingDisplay) {
+    [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
+    mPendingDisplay = YES;
+  }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (!mPendingDirtyRects)
     mPendingDirtyRects = [[NSMutableArray alloc] initWithCapacity:1];
   [mPendingDirtyRects addObject:[NSValue valueWithRect:invalidRect]];
-  [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
+  if (!mPendingDisplay) {
+    [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
+    mPendingDisplay = YES;
+  }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 // Clears the queue of any pending invalides
 - (void)processPendingRedraws
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (mPendingFullDisplay) {
     [self setNeedsDisplay:YES];
   }
-  else {
+  else if (mPendingDirtyRects) {
     unsigned int count = [mPendingDirtyRects count];
     for (unsigned int i = 0; i < count; ++i) {
       [self setNeedsDisplayInRect:[[mPendingDirtyRects objectAtIndex:i] rectValue]];
     }
   }
   mPendingFullDisplay = NO;
+  mPendingDisplay = NO;
   [mPendingDirtyRects release];
   mPendingDirtyRects = nil;
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (void)setNeedsDisplayInRect:(NSRect)aRect
 {