Bug 1095210 - Record native invalidations in -[BaseWindow _setNeedsDisplayInRect:] so that invalidations occurring during -[ChildView viewWillDraw] are not lost. r=smichaud, a=lsblakk
authorMarkus Stange <mstange@themasta.com>
Fri, 07 Nov 2014 13:11:48 -0500
changeset 233833 39f4ba799a455fff676996e4642a473ebc9bdf57
parent 233832 519f357d4c77666c8be1b4d62bdd1844504cf798
child 233834 f76be16501c9fc2d452062950ea44eb4779d209d
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud, lsblakk
bugs1095210
milestone35.0a2
Bug 1095210 - Record native invalidations in -[BaseWindow _setNeedsDisplayInRect:] so that invalidations occurring during -[ChildView viewWillDraw] are not lost. r=smichaud, a=lsblakk
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -577,17 +577,16 @@ public:
 
   NS_IMETHOD        ReparentNativeWidget(nsIWidget* aNewParent);
 
   mozilla::widget::TextInputHandler* GetTextInputHandler()
   {
     return mTextInputHandler;
   }
 
-  void              NotifyDirtyRegion(const nsIntRegion& aDirtyRegion);
   void              ClearVibrantAreas();
   NSColor*          VibrancyFillColorForWidgetType(uint8_t aWidgetType);
 
   // unit conversion convenience functions
   int32_t           CocoaPointsToDevPixels(CGFloat aPts) const {
     return nsCocoaUtils::CocoaPointsToDevPixels(aPts, BackingScaleFactor());
   }
   nsIntPoint        CocoaPointsToDevPixels(const NSPoint& aPt) const {
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2115,25 +2115,16 @@ nsChildView::NewCompositorParent(int aSu
       [EventThreadRunner start];
     }
     gNumberOfWidgetsNeedingEventThread++;
   }
 
   return compositor;
 }
 
-void
-nsChildView::NotifyDirtyRegion(const nsIntRegion& aDirtyRegion)
-{
-  if ([(ChildView*)mView isCoveringTitlebar]) {
-    // We store the dirty region so that we know what to repaint in the titlebar.
-    mDirtyTitlebarRegion.Or(mDirtyTitlebarRegion, aDirtyRegion);
-  }
-}
-
 nsIntRect
 nsChildView::RectContainingTitlebarControls()
 {
   // Start with a thin strip at the top of the window for the highlight line.
   NSRect rect = NSMakeRect(0, 0, [mView bounds].size.width,
                            [(ChildView*)mView cornerRadius]);
 
   // Add the rects of the titlebar controls.
@@ -2337,57 +2328,50 @@ CreateCGContext(const nsIntSize& aSize)
 
   return ctx;
 }
 
 // When this method is entered, mEffectsLock is already being held.
 void
 nsChildView::UpdateTitlebarCGContext()
 {
-  nsIntRegion dirtyTitlebarRegion;
-  dirtyTitlebarRegion.And(mDirtyTitlebarRegion, mTitlebarRect);
-  mDirtyTitlebarRegion.SetEmpty();
-
   if (mTitlebarRect.IsEmpty()) {
     ReleaseTitlebarCGContext();
     return;
   }
 
+  NSRect titlebarRect = DevPixelsToCocoaPoints(mTitlebarRect);
+  NSRect dirtyRect = [mView convertRect:[(BaseWindow*)[mView window] getAndResetNativeDirtyRect] fromView:nil];
+  NSRect dirtyTitlebarRect = NSIntersectionRect(titlebarRect, dirtyRect);
+
   nsIntSize texSize = RectTextureImage::TextureSizeForSize(mTitlebarRect.Size());
   if (!mTitlebarCGContext ||
       CGBitmapContextGetWidth(mTitlebarCGContext) != size_t(texSize.width) ||
       CGBitmapContextGetHeight(mTitlebarCGContext) != size_t(texSize.height)) {
-    dirtyTitlebarRegion = mTitlebarRect;
+    dirtyTitlebarRect = titlebarRect;
 
     ReleaseTitlebarCGContext();
 
     mTitlebarCGContext = CreateCGContext(texSize);
   }
 
-  if (dirtyTitlebarRegion.IsEmpty())
+  if (NSIsEmptyRect(dirtyTitlebarRect)) {
     return;
+  }
 
   CGContextRef ctx = mTitlebarCGContext;
 
   CGContextSaveGState(ctx);
 
-  nsTArray<CGRect> rects;
-  nsIntRegionRectIterator iter(dirtyTitlebarRegion);
-  for (;;) {
-    const nsIntRect* r = iter.Next();
-    if (!r)
-      break;
-    rects.AppendElement(CGRectMake(r->x, r->y, r->width, r->height));
-  }
-  CGContextClipToRects(ctx, rects.Elements(), rects.Length());
-
-  CGContextClearRect(ctx, CGRectMake(0, 0, texSize.width, texSize.height));
-
   double scale = BackingScaleFactor();
   CGContextScaleCTM(ctx, scale, scale);
+
+  CGContextClipToRect(ctx, NSRectToCGRect(dirtyTitlebarRect));
+  CGContextClearRect(ctx, NSRectToCGRect(dirtyTitlebarRect));
+
   NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
 
   CGContextSaveGState(ctx);
 
   BaseWindow* window = (BaseWindow*)[mView window];
   NSView* frameView = [[window contentView] superview];
   if (![frameView isFlipped]) {
     CGContextTranslateCTM(ctx, 0, [frameView bounds].size.height);
@@ -2399,18 +2383,18 @@ nsChildView::UpdateTitlebarCGContext()
   // Draw the title string.
   if ([window wantsTitleDrawn] && [frameView respondsToSelector:@selector(_drawTitleBar:)]) {
     [frameView _drawTitleBar:[frameView bounds]];
   }
 
   // Draw the titlebar controls into the titlebar image.
   for (id view in [window titlebarControls]) {
     NSRect viewFrame = [view frame];
-    nsIntRect viewRect = CocoaPointsToDevPixels([mView convertRect:viewFrame fromView:frameView]);
-    if (!dirtyTitlebarRegion.Intersects(viewRect)) {
+    NSRect viewRect = [mView convertRect:viewFrame fromView:frameView];
+    if (!NSIntersectsRect(dirtyTitlebarRect, viewRect)) {
       continue;
     }
     // All of the titlebar controls we're interested in are subclasses of
     // NSButton.
     if (![view isKindOfClass:[NSButton class]]) {
       continue;
     }
     NSButton *button = (NSButton *) view;
@@ -2460,17 +2444,17 @@ nsChildView::UpdateTitlebarCGContext()
 
   DrawTitlebarHighlight([frameView bounds].size, [(ChildView*)mView cornerRadius],
                         DevPixelsToCocoaPoints(1));
 
   [NSGraphicsContext setCurrentContext:oldContext];
 
   CGContextRestoreGState(ctx);
 
-  mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion);
+  mUpdatedTitlebarRegion.OrWith(CocoaPointsToDevPixels(dirtyTitlebarRect));
 }
 
 // This method draws an overlay in the top of the window which contains the
 // titlebar controls (e.g. close, min, zoom, fullscreen) and the titlebar
 // highlight effect.
 // This is necessary because the real titlebar controls are covered by our
 // OpenGL context. Note that in terms of the NSView hierarchy, our ChildView
 // is actually below the titlebar controls - that's why hovering and clicking
@@ -4060,21 +4044,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
       NS_ADDREF(mGeckoChild);
       [widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)mGeckoChild]];
       [self performSelector:@selector(releaseWidgets:)
                  withObject:widgetArray
                  afterDelay:0];
     }
 
     if ([self isUsingOpenGL]) {
-      // When our view covers the titlebar, we need to repaint the titlebar
-      // texture buffer when, for example, the window buttons are hovered.
-      // So we notify our nsChildView about any areas needing repainting.
-      mGeckoChild->NotifyDirtyRegion([self nativeDirtyRegionWithBoundingRect:[self bounds]]);
-
       if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
         ClientLayerManager *manager = static_cast<ClientLayerManager*>(mGeckoChild->GetLayerManager());
         manager->AsShadowForwarder()->WindowOverlayChanged();
       }
     }
 
     mGeckoChild->WillPaintWindow();
   }
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -72,16 +72,18 @@ typedef struct _nsCocoaWindowList {
 
   // DPI cache. Getting the physical screen size (CGDisplayScreenSize)
   // is ridiculously slow, so we cache it in the toplevel window for all
   // descendants to use.
   float mDPI;
 
   NSTrackingArea* mTrackingArea;
 
+  NSRect mDirtyRect;
+
   BOOL mBeingShown;
   BOOL mDrawTitle;
   BOOL mBrightTitlebarForeground;
 }
 
 - (void)importState:(NSDictionary*)aState;
 - (NSMutableDictionary*)exportState;
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
@@ -111,16 +113,18 @@ typedef struct _nsCocoaWindowList {
 - (BOOL)wantsTitleDrawn;
 
 - (void)setUseBrightTitlebarForeground:(BOOL)aBrightForeground;
 - (BOOL)useBrightTitlebarForeground;
 
 - (void)disableSetNeedsDisplay;
 - (void)enableSetNeedsDisplay;
 
+- (NSRect)getAndResetNativeDirtyRect;
+
 @end
 
 @interface NSWindow (Undocumented)
 
 // If a window has been explicitly removed from the "window cache" (to
 // deactivate it), it's sometimes necessary to "reset" it to reactivate it
 // (and put it back in the "window cache").  One way to do this, which Apple
 // often uses, is to set the "window number" to '-1' and then back to its
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -2635,16 +2635,17 @@ static NSMutableSet *gSwizzledFrameViewC
   [super initWithContentRect:aContentRect styleMask:aStyle backing:aBufferingType defer:aFlag];
   mState = nil;
   mActiveTitlebarColor = nil;
   mInactiveTitlebarColor = nil;
   mScheduledShadowInvalidation = NO;
   mDisabledNeedsDisplay = NO;
   mDPI = GetDPI(self);
   mTrackingArea = nil;
+  mDirtyRect = NSZeroRect;
   mBeingShown = NO;
   mDrawTitle = NO;
   mBrightTitlebarForeground = NO;
   [self updateTrackingArea];
 
   return self;
 }
 
@@ -2856,19 +2857,27 @@ static const NSString* kStateShowsToolba
 - (void)_setNeedsDisplayInRect:(NSRect)aRect
 {
   // Prevent unnecessary invalidations due to moving NSViews (e.g. for plugins)
   if (!mDisabledNeedsDisplay) {
     // This method is only called by Cocoa, so when we're here, we know that
     // it's available and don't need to check whether our superclass responds
     // to the selector.
     [super _setNeedsDisplayInRect:aRect];
+    mDirtyRect = NSUnionRect(mDirtyRect, aRect);
   }
 }
 
+- (NSRect)getAndResetNativeDirtyRect
+{
+  NSRect dirtyRect = mDirtyRect;
+  mDirtyRect = NSZeroRect;
+  return dirtyRect;
+}
+
 - (void)updateContentViewSize
 {
   NSRect rect = [self contentRectForFrameRect:[self frame]];
   [[self contentView] setFrameSize:rect.size];
 }
 
 // Possibly move the titlebar buttons.
 - (void)reflowTitlebarElements