Bug 1533562 - Always make the content view of ToolbarWindows cover the entire window. r=spohl
☠☠ backed out by d2f707cb83c9 ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Fri, 26 Apr 2019 17:26:39 +0000
changeset 530366 00ffda400dc5824428e78eea2a994e02bfb39d75
parent 530365 710d3c0129de293e625a284b450af7024062449d
child 530367 02adcc70efbe3e0719edcec48c3e282eb964bb5a
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersspohl
bugs1533562
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1533562 - Always make the content view of ToolbarWindows cover the entire window. r=spohl Differential Revision: https://phabricator.services.mozilla.com/D22645
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -54,16 +54,26 @@ typedef struct _nsCocoaWindowList {
   nsTouchBar* mTouchBar;
 }
 
 - (void)importState:(NSDictionary*)aState;
 - (NSMutableDictionary*)exportState;
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
 - (BOOL)drawsContentsIntoWindowFrame;
 
+// These two methods are like contentRectForFrameRect and frameRectForContentRect,
+// but they deal with the rect of the window's "main ChildView" instead of the
+// rect of the window's content view. The two are sometimes sized differently: The
+// window's content view always covers the entire window, whereas the ChildView
+// only covers the full window when drawsContentsIntoWindowFrame is YES. When
+// drawsContentsIntoWindowFrame is NO, there's a titlebar-sized gap above the
+// ChildView within the content view.
+- (NSRect)childViewRectForFrameRect:(NSRect)aFrameRect;
+- (NSRect)frameRectForChildViewRect:(NSRect)aChildViewRect;
+
 - (void)mouseEntered:(NSEvent*)aEvent;
 - (void)mouseExited:(NSEvent*)aEvent;
 - (void)mouseMoved:(NSEvent*)aEvent;
 - (void)updateTrackingArea;
 - (NSView*)trackingAreaView;
 
 - (void)setBeingShown:(BOOL)aValue;
 - (BOOL)isBeingShown;
@@ -227,16 +237,17 @@ class nsCocoaWindow final : public nsBas
   void ReleaseFullscreenTransitionAnimation() {
     MOZ_ASSERT(mFullscreenTransitionAnimation, "Should only be called when there is animation");
     [mFullscreenTransitionAnimation release];
     mFullscreenTransitionAnimation = nil;
   }
 
   virtual void Resize(double aWidth, double aHeight, bool aRepaint) override;
   virtual void Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) override;
+  NSRect GetClientCocoaRect();
   virtual LayoutDeviceIntRect GetClientBounds() override;
   virtual LayoutDeviceIntRect GetScreenBounds() override;
   void ReportMoveEvent();
   void ReportSizeEvent();
   virtual void SetCursor(nsCursor aDefaultCursor, imgIContainer* aCursorImage, uint32_t aHotspotX,
                          uint32_t aHotspotY) override;
 
   CGFloat BackingScaleFactor();
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -453,17 +453,17 @@ nsresult nsCocoaWindow::CreateNativeWind
   [mWindow setRestorable:NO];
   [mWindow disableSnapshotRestoration];
 
   // setup our notification delegate. Note that setDelegate: does NOT retain.
   mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
   [mWindow setDelegate:mDelegate];
 
   // Make sure that the content rect we gave has been honored.
-  NSRect wantedFrame = [mWindow frameRectForContentRect:contentRect];
+  NSRect wantedFrame = [mWindow frameRectForChildViewRect:contentRect];
   if (!NSEqualRects([mWindow frame], wantedFrame)) {
     // This can happen when the window is not on the primary screen.
     [mWindow setFrame:wantedFrame display:NO];
   }
   UpdateBounds();
 
   if (mWindowType == eWindowType_invisible) {
     [mWindow setLevel:kCGDesktopWindowLevelKey];
@@ -1099,17 +1099,17 @@ void nsCocoaWindow::ConstrainPosition(bo
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 void nsCocoaWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   // Popups can be smaller than (60, 60)
   NSRect rect = (mWindowType == eWindowType_popup) ? NSZeroRect : NSMakeRect(0.0, 0.0, 60, 60);
-  rect = [mWindow frameRectForContentRect:rect];
+  rect = [mWindow frameRectForChildViewRect:rect];
 
   CGFloat scaleFactor = BackingScaleFactor();
 
   SizeConstraints c = aConstraints;
   c.mMinSize.width = std::max(nsCocoaUtils::CocoaPointsToDevPixels(rect.size.width, scaleFactor),
                               c.mMinSize.width);
   c.mMinSize.height = std::max(nsCocoaUtils::CocoaPointsToDevPixels(rect.size.height, scaleFactor),
                                c.mMinSize.height);
@@ -1479,33 +1479,32 @@ void nsCocoaWindow::Resize(double aX, do
 }
 
 // Coordinates are desktop pixels
 void nsCocoaWindow::Resize(double aWidth, double aHeight, bool aRepaint) {
   double invScale = 1.0 / BackingScaleFactor();
   DoResize(mBounds.x * invScale, mBounds.y * invScale, aWidth, aHeight, aRepaint, true);
 }
 
+// Return the area that the Gecko ChildView in our window should cover, as an
+// NSRect in screen coordinates (with 0,0 being the bottom left corner of the
+// primary screen).
+NSRect nsCocoaWindow::GetClientCocoaRect() {
+  if (!mWindow) {
+    return NSZeroRect;
+  }
+
+  return [mWindow childViewRectForFrameRect:[mWindow frame]];
+}
+
 LayoutDeviceIntRect nsCocoaWindow::GetClientBounds() {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   CGFloat scaleFactor = BackingScaleFactor();
-  if (!mWindow) {
-    return nsCocoaUtils::CocoaRectToGeckoRectDevPix(NSZeroRect, scaleFactor);
-  }
-
-  NSRect r;
-  if ([mWindow isKindOfClass:[ToolbarWindow class]] &&
-      [(ToolbarWindow*)mWindow drawsContentsIntoWindowFrame]) {
-    r = [mWindow frame];
-  } else {
-    r = [mWindow contentRectForFrameRect:[mWindow frame]];
-  }
-
-  return nsCocoaUtils::CocoaRectToGeckoRectDevPix(r, scaleFactor);
+  return nsCocoaUtils::CocoaRectToGeckoRectDevPix(GetClientCocoaRect(), scaleFactor);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntRect(0, 0, 0, 0));
 }
 
 void nsCocoaWindow::UpdateBounds() {
   NSRect frame = NSZeroRect;
   if (mWindow) {
     frame = [mWindow frame];
@@ -1851,24 +1850,18 @@ nsresult nsCocoaWindow::SetFocus(bool aS
   }
 
   return NS_OK;
 }
 
 LayoutDeviceIntPoint nsCocoaWindow::WidgetToScreenOffset() {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
-  NSRect rect = NSZeroRect;
-  LayoutDeviceIntRect r;
-  if (mWindow) {
-    rect = [mWindow contentRectForFrameRect:[mWindow frame]];
-  }
-  r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(rect, BackingScaleFactor());
-
-  return r.TopLeft();
+  return nsCocoaUtils::CocoaRectToGeckoRectDevPix(GetClientCocoaRect(), BackingScaleFactor())
+      .TopLeft();
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntPoint(0, 0));
 }
 
 LayoutDeviceIntPoint nsCocoaWindow::GetClientOffset() {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   LayoutDeviceIntRect clientRect = GetClientBounds();
@@ -1891,18 +1884,18 @@ LayoutDeviceIntSize nsCocoaWindow::Clien
   // i.e. for windows where [mWindow drawsContentsIntoWindowFrame] is NO.
   //
   // So we call frameRectForContentRect on NSWindow here, instead of mWindow, so
   // that we don't run into our override if this window is a window that draws
   // its content into the titlebar.
   //
   // This is the same thing the windows widget does, but we probably should fix
   // that, see bug 1445738.
-  unsigned int features = [mWindow styleMask];
-  NSRect inflatedRect = [NSWindow frameRectForContentRect:rect styleMask:features];
+  NSUInteger styleMask = [mWindow styleMask];
+  NSRect inflatedRect = [NSWindow frameRectForContentRect:rect styleMask:styleMask];
   r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(inflatedRect, backingScale);
   return r.Size();
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntSize(0, 0));
 }
 
 nsMenuBarX* nsCocoaWindow::GetMenuBar() { return mMenuBar; }
 
@@ -2653,17 +2646,16 @@ static NSMutableSet* gSwizzledFrameViewC
 
 @interface NSView (NSVisualEffectViewSetMaskImage)
 - (void)setMaskImage:(NSImage*)image;
 @end
 
 @interface BaseWindow (Private)
 - (void)removeTrackingArea;
 - (void)cursorUpdated:(NSEvent*)aEvent;
-- (void)updateContentViewSize;
 - (void)reflowTitlebarElements;
 @end
 
 @implementation BaseWindow
 
 // The frame of a window is implemented using undocumented NSView subclasses.
 // We offset the window buttons by overriding the methods _closeButtonOrigin
 // and _fullScreenButtonOrigin on these frame view classes. The class which is
@@ -2851,28 +2843,43 @@ static const NSString* kStateCollectionB
             forKey:kStateCollectionBehavior];
   return state;
 }
 
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState {
   bool changed = (aState != mDrawsIntoWindowFrame);
   mDrawsIntoWindowFrame = aState;
   if (changed) {
-    [self updateContentViewSize];
     [self reflowTitlebarElements];
     if ([self respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) {
       [self setTitlebarAppearsTransparent:mDrawsIntoWindowFrame];
     }
   }
 }
 
 - (BOOL)drawsContentsIntoWindowFrame {
   return mDrawsIntoWindowFrame;
 }
 
+- (NSRect)childViewRectForFrameRect:(NSRect)aFrameRect {
+  if (mDrawsIntoWindowFrame) {
+    return aFrameRect;
+  }
+  NSUInteger styleMask = [self styleMask];
+  return [NSWindow contentRectForFrameRect:aFrameRect styleMask:styleMask];
+}
+
+- (NSRect)frameRectForChildViewRect:(NSRect)aChildViewRect {
+  if (mDrawsIntoWindowFrame) {
+    return aChildViewRect;
+  }
+  NSUInteger styleMask = [self styleMask];
+  return [NSWindow frameRectForContentRect:aChildViewRect styleMask:styleMask];
+}
+
 - (void)setWantsTitleDrawn:(BOOL)aDrawTitle {
   mDrawTitle = aDrawTitle;
   if ([self respondsToSelector:@selector(setTitleVisibility:)]) {
     [self setTitleVisibility:mDrawTitle ? NSWindowTitleVisible : NSWindowTitleHidden];
   }
 }
 
 - (BOOL)wantsTitleDrawn {
@@ -2951,68 +2958,39 @@ static const NSString* kStateCollectionB
 }
 
 - (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 {
   NSView* frameView = [[self contentView] superview];
   if ([frameView respondsToSelector:@selector(_tileTitlebarAndRedisplay:)]) {
     [frameView _tileTitlebarAndRedisplay:NO];
   }
 }
 
 // Override methods that translate between content rect and frame rect.
 - (NSRect)contentRectForFrameRect:(NSRect)aRect {
-  if ([self drawsContentsIntoWindowFrame]) {
-    return aRect;
-  }
-  return [super contentRectForFrameRect:aRect];
+  return aRect;
 }
 
 - (NSRect)contentRectForFrameRect:(NSRect)aRect styleMask:(NSUInteger)aMask {
-  if ([self drawsContentsIntoWindowFrame]) {
-    return aRect;
-  }
-  // Call the instance method on super, if it exists (it's undocumented so we
-  // shouldn't rely on it), or fall back to the (documented) class method.
-  if ([NSWindow instancesRespondToSelector:@selector(contentRectForFrameRect:styleMask:)]) {
-    return [super contentRectForFrameRect:aRect styleMask:aMask];
-  } else {
-    return [NSWindow contentRectForFrameRect:aRect styleMask:aMask];
-  }
+  return aRect;
 }
 
 - (NSRect)frameRectForContentRect:(NSRect)aRect {
-  if ([self drawsContentsIntoWindowFrame]) {
-    return aRect;
-  }
-  return [super frameRectForContentRect:aRect];
+  return aRect;
 }
 
 - (NSRect)frameRectForContentRect:(NSRect)aRect styleMask:(NSUInteger)aMask {
-  if ([self drawsContentsIntoWindowFrame]) {
-    return aRect;
-  }
-  // Call the instance method on super, if it exists (it's undocumented so we
-  // shouldn't rely on it), or fall back to the (documented) class method.
-  if ([NSWindow instancesRespondToSelector:@selector(frameRectForContentRect:styleMask:)]) {
-    return [super frameRectForContentRect:aRect styleMask:aMask];
-  } else {
-    return [NSWindow frameRectForContentRect:aRect styleMask:aMask];
-  }
+  return aRect;
 }
 
 - (void)setContentView:(NSView*)aView {
   [super setContentView:aView];
 
   // Now move the contentView to the bottommost layer so that it's guaranteed
   // to be under the window buttons.
   NSView* frameView = [aView superview];
@@ -3130,28 +3108,40 @@ static const NSString* kStateCollectionB
 // query the window for its titlebar height when drawing the toolbar.
 //
 // Note that in drawsContentsIntoWindowFrame mode, titlebar drawing works in a
 // completely different way: In that mode, the window's mainChildView will
 // cover the titlebar completely and nothing that happens in the window
 // background will reach the screen.
 @implementation ToolbarWindow
 
-- (id)initWithContentRect:(NSRect)aContentRect
+- (id)initWithContentRect:(NSRect)aChildViewRect
                 styleMask:(NSUInteger)aStyle
                   backing:(NSBackingStoreType)aBufferingType
                     defer:(BOOL)aFlag {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
-  if ((self = [super initWithContentRect:aContentRect
+  // We treat aChildViewRect as the rectangle that the window's main ChildView
+  // should be sized to. Get the right frameRect for the requested child view
+  // rect.
+  NSRect frameRect = [NSWindow frameRectForContentRect:aChildViewRect styleMask:aStyle];
+
+  // -[NSWindow initWithContentRect:styleMask:backing:defer:] calls
+  // [self frameRectForContentRect:styleMask:] to convert the supplied content
+  // rect to the window's frame rect. We've overridden that method to be a
+  // pass-through function. So, in order to get the intended frameRect, we need
+  // to supply frameRect itself as the "content rect".
+  NSRect contentRect = frameRect;
+
+  if ((self = [super initWithContentRect:contentRect
                                styleMask:aStyle
                                  backing:aBufferingType
                                    defer:aFlag])) {
     mUnifiedToolbarHeight = 22.0f;
-    mSheetAttachmentPosition = aContentRect.size.height;
+    mSheetAttachmentPosition = aChildViewRect.size.height;
     mWindowButtonsRect = NSZeroRect;
     mFullScreenButtonRect = NSZeroRect;
   }
   return self;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
@@ -3174,20 +3164,20 @@ static const NSString* kStateCollectionB
 // Returns the unified height of titlebar + toolbar.
 - (CGFloat)unifiedToolbarHeight {
   return mUnifiedToolbarHeight;
 }
 
 - (CGFloat)titlebarHeight {
   // We use the original content rect here, not what we return from
   // [self contentRectForFrameRect:], because that would give us a
-  // titlebarHeight of zero in drawsContentsIntoWindowFrame mode.
+  // titlebarHeight of zero.
   NSRect frameRect = [self frame];
-  NSRect originalContentRect = [NSWindow contentRectForFrameRect:frameRect
-                                                       styleMask:[self styleMask]];
+  NSUInteger styleMask = [self styleMask];
+  NSRect originalContentRect = [NSWindow contentRectForFrameRect:frameRect styleMask:styleMask];
   return NSMaxY(frameRect) - NSMaxY(originalContentRect);
 }
 
 // Stores the complete height of titlebar + toolbar.
 - (void)setUnifiedToolbarHeight:(CGFloat)aHeight {
   if (aHeight == mUnifiedToolbarHeight) return;
 
   mUnifiedToolbarHeight = aHeight;