Bug 621762 - Change the way native windows are notified about toolbars. r=roc, a=betaN
authorMarkus Stange <mstange@themasta.com>
Tue, 11 Jan 2011 14:03:16 +0100
changeset 60289 6cfffe34531c366309ad5842b68fd374d22950e4
parent 60288 57eb3d4405930d4905e47b45a458e4a958075f66
child 60290 d414fbea7ba3c74b48f7575897fb790fc8c909c5
push idunknown
push userunknown
push dateunknown
reviewersroc, betaN
bugs621762
milestone2.0b10pre
Bug 621762 - Change the way native windows are notified about toolbars. r=roc, a=betaN
gfx/src/nsITheme.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
widget/public/nsIWidget.h
widget/src/cocoa/nsChildView.h
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsCocoaWindow.h
widget/src/cocoa/nsCocoaWindow.mm
widget/src/cocoa/nsNativeThemeCocoa.h
widget/src/cocoa/nsNativeThemeCocoa.mm
widget/src/xpwidgets/nsBaseWidget.h
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -97,34 +97,17 @@ public:
    */
   NS_IMETHOD DrawWidgetBackground(nsIRenderingContext* aContext,
                                   nsIFrame* aFrame,
                                   PRUint8 aWidgetType,
                                   const nsRect& aRect,
                                   const nsRect& aDirtyRect) = 0;
 
   /**
-   * Notifies the theme engine that a particular themed widget exists
-   * at the given rectangle within the window aWindow.
-   * For certain appearance values (currently only
-   * NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR and NS_THEME_TOOLBAR) this gets
-   * called during every paint to a window, for every themed widget of
-   * the right type within the
-   * window, except for themed widgets which are transformed or have
-   * effects applied to them (e.g. CSS opacity or filters).
-   * Note that a DrawWidgetBackground for the widget might not be called
-   * during the paint, since ThebesLayers can cache rendered content.
-   * This could sometimes be called during display list construction
-   * outside of painting.
-   * If called during painting, it will be called before we actually
-   * paint anything.
-   * 
-   * @param aWidgetType the -moz-appearance value for the themed widget
-   * @param aRect the device-pixel rect within aWindow for the themed
-   * widget
+   * XXX Unused. This is only here because the interface is frozen for 2.0.
    */
   virtual void RegisterWidgetGeometry(nsIWidget* aWindow,
                                       PRUint8 aWidgetType,
                                       const nsIntRect& aRect) {}
 
   /**
    * Get the computed CSS border for the widget, in pixels.
    */
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -256,16 +256,27 @@ void
 nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
                                      const nsRect& aDirtyRect) {
   if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) {
     // Must have not allocated a state for this presshell, presumably due
     // to OOM.
     return;
   }
 
+  // If we're finished building display list items for painting of the outermost
+  // pres shell, notify the widget about any toolbars we've encountered.
+  if (mIsPaintingToWindow && mPresShellStates.Length() == 1) {
+    nsIWidget* widget = aReferenceFrame->GetNearestWidget();
+    if (widget) {
+      nsIWidget_MOZILLA_2_0_BRANCH* widget2 =
+        static_cast<nsIWidget_MOZILLA_2_0_BRANCH*>(widget);
+      widget2->UpdateThemeGeometries(CurrentPresShellState()->mThemeGeometries);
+    }
+  }
+
   // Unmark and pop off the frames marked for display in this pres shell.
   PRUint32 firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
   for (PRUint32 i = firstFrameForShell;
        i < mFramesMarkedForDisplay.Length(); ++i) {
     UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
   }
   mFramesMarkedForDisplay.SetLength(firstFrameForShell);
   mPresShellStates.SetLength(mPresShellStates.Length() - 1);
@@ -710,59 +721,48 @@ PRBool nsDisplayItem::RecomputeVisibilit
 
 void nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
                                 nsIRenderingContext* aCtx) {
   aCtx->SetColor(mColor);
   aCtx->FillRect(mVisibleRect);
 }
 
 static void
-RegisterThemeWidgetGeometry(nsIFrame* aFrame)
+RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
 {
-  nsPresContext* presContext = aFrame->PresContext();
-  nsITheme* theme = presContext->GetTheme();
-  if (!theme)
-    return;
-
   nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
-  nsIWidget* widget = displayRoot->GetNearestWidget();
-  // If the display root doesn't have a widget, just bail. Something
-  // weird is going on, maybe we're printing?
-  if (!widget)
-    return;
 
   for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
     // Bail out if we're in a transformed subtree
     if (f->IsTransformed())
       return;
     // Bail out if we're not in the displayRoot's document
     if (!f->GetParent() && f != displayRoot)
       return;
   }
 
   nsRect borderBox(aFrame->GetOffsetTo(displayRoot), aFrame->GetSize());
-  theme->RegisterWidgetGeometry(widget,
-      aFrame->GetStyleDisplay()->mAppearance,
-      borderBox.ToNearestPixels(presContext->AppUnitsPerDevPixel()));
+  aBuilder->RegisterThemeGeometry(aFrame->GetStyleDisplay()->mAppearance,
+      borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel()));
 }
 
 nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
                                          nsIFrame* aFrame)
   : nsDisplayItem(aBuilder, aFrame),
     mSnappingEnabled(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform())
 {
   MOZ_COUNT_CTOR(nsDisplayBackground);
   const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
   mIsThemed = mFrame->IsThemed(disp, &mThemeTransparency);
 
-  // Perform necessary RegisterWidgetGeometry
+  // Perform necessary RegisterThemeGeometry
   if (mIsThemed &&
       (disp->mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
        disp->mAppearance == NS_THEME_TOOLBAR)) {
-    RegisterThemeWidgetGeometry(aFrame);
+    RegisterThemeGeometry(aBuilder, aFrame);
   }
 }
 
 // Helper for RoundedRectIntersectsRect.
 static PRBool
 CheckCorner(nscoord aXOffset, nscoord aYOffset,
             nscoord aXRadius, nscoord aYRadius)
 {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -122,16 +122,17 @@ class nsDisplayItem;
  * coordinate system for all display list items. Some of the parameters are
  * available from the prescontext/presshell, but we copy them into the builder
  * for faster/more convenient access.
  */
 class nsDisplayListBuilder {
 public:
   typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
   typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
+  typedef nsIWidget::ThemeGeometry ThemeGeometry;
 
   /**
    * @param aReferenceFrame the frame at the root of the subtree; its origin
    * is the origin of the reference coordinate system for this display list
    * @param aIsForEvents PR_TRUE if we're creating this list in order to
    * determine which frame is under the mouse position
    * @param aBuildCaret whether or not we should include the caret in any
    * display lists that we make.
@@ -366,17 +367,39 @@ public:
    * the display list, even though it doesn't intersect the dirty
    * rect, because it may have out-of-flows that do so.
    */
   bool ShouldDescendIntoFrame(nsIFrame* aFrame) const {
     return
       (aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) ||
       GetIncludeAllOutOfFlows();
   }
-  
+
+  /**
+   * Notifies the builder that a particular themed widget exists
+   * at the given rectangle within the currently built display list.
+   * For certain appearance values (currently only
+   * NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR and NS_THEME_TOOLBAR) this gets
+   * called during every display list construction, for every themed widget of
+   * the right type within the display list, except for themed widgets which
+   * are transformed or have effects applied to them (e.g. CSS opacity or
+   * filters).
+   *
+   * @param aWidgetType the -moz-appearance value for the themed widget
+   * @param aRect the device-pixel rect relative to the widget's displayRoot
+   * for the themed widget
+   */
+  void RegisterThemeGeometry(PRUint8 aWidgetType,
+                             const nsIntRect& aRect) {
+    if (mIsPaintingToWindow) {
+      ThemeGeometry geometry(aWidgetType, aRect);
+      CurrentPresShellState()->mThemeGeometries.AppendElement(geometry);
+    }
+  }
+
   /**
    * Allocate memory in our arena. It will only be freed when this display list
    * builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
    * destructors are called as soon as the item is no longer used.
    */
   void* Allocate(size_t aSize);
   
   /**
@@ -429,16 +452,17 @@ public:
   }
 
 private:
   struct PresShellState {
     nsIPresShell* mPresShell;
     nsIFrame*     mCaretFrame;
     PRUint32      mFirstFrameMarkedForDisplay;
     PRPackedBool  mIsBackgroundOnly;
+    nsAutoTArray<ThemeGeometry,2> mThemeGeometries;
   };
   PresShellState* CurrentPresShellState() {
     NS_ASSERTION(mPresShellStates.Length() > 0,
                  "Someone forgot to enter a presshell");
     return &mPresShellStates[mPresShellStates.Length() - 1];
   }
 
   FrameLayerBuilder              mLayerBuilder;
--- a/widget/public/nsIWidget.h
+++ b/widget/public/nsIWidget.h
@@ -257,16 +257,29 @@ class nsIWidget : public nsISupports {
 #ifdef MOZ_IPC
   protected:
     typedef mozilla::dom::PBrowserChild PBrowserChild;
 #endif
 
   public:
     typedef mozilla::layers::LayerManager LayerManager;
 
+    // Used in UpdateThemeGeometries.
+    struct ThemeGeometry {
+      // The -moz-appearance value for the themed widget
+      PRUint8 mWidgetType;
+      // The device-pixel rect within the window for the themed widget
+      nsIntRect mRect;
+
+      ThemeGeometry(PRUint8 aWidgetType, const nsIntRect& aRect)
+       : mWidgetType(aWidgetType)
+       , mRect(aRect)
+      { }
+    };
+
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWIDGET_IID)
 
     nsIWidget()
       : mLastChild(nsnull)
       , mPrevSibling(nsnull)
     {}
 
         
@@ -1402,13 +1415,27 @@ class nsIWidget_MOZILLA_2_0_BRANCH : pub
 
     /**
      * Called after the LayerManager draws the layer tree
      *
      * @param aManager The drawing LayerManager.
      * @param aRect Current widget rect that is being drawn.
      */
     virtual void DrawOver(LayerManager* aManager, nsIntRect aRect) = 0;
+
+    /**
+     * Called when Gecko knows which themed widgets exist in this window.
+     * The passed array contains an entry for every themed widget of the right
+     * type (currently only NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR and
+     * NS_THEME_TOOLBAR) within the window, except for themed widgets which are
+     * transformed or have effects applied to them (e.g. CSS opacity or
+     * filters).
+     * This could sometimes be called during display list construction
+     * outside of painting.
+     * If called during painting, it will be called before we actually
+     * paint anything.
+     */
+    virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIWidget_MOZILLA_2_0_BRANCH, NS_IWIDGET_MOZILLA_2_0_BRANCH_IID)
 
 #endif // nsIWidget_h__
--- a/widget/src/cocoa/nsChildView.h
+++ b/widget/src/cocoa/nsChildView.h
@@ -390,16 +390,18 @@ public:
   
 #ifdef ACCESSIBILITY
   already_AddRefed<nsAccessible> GetDocumentAccessible();
 #endif
 
   virtual gfxASurface* GetThebesSurface();
   virtual void DrawOver(LayerManager* aManager, nsIntRect aRect);
 
+  virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries);
+
   NS_IMETHOD BeginSecureKeyboardInput();
   NS_IMETHOD EndSecureKeyboardInput();
 
   void              HidePlugin();
   void              UpdatePluginPort();
 
   void              ResetParent();
 
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -66,16 +66,17 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsIServiceManager.h"
 #include "nsILocalFile.h"
 #include "nsILocalFileMac.h"
 #include "nsGfxCIID.h"
 #include "nsIMenuRollup.h"
 #include "nsIDOMSimpleGestureEvent.h"
 #include "nsIPluginInstance.h"
+#include "nsThemeConstants.h"
 
 #include "nsDragService.h"
 #include "nsClipboard.h"
 #include "nsCursorManager.h"
 #include "nsWindowMap.h"
 #include "nsCocoaUtils.h"
 #include "nsMenuUtilsX.h"
 #include "nsMenuBarX.h"
@@ -184,19 +185,16 @@ PRUint32 nsChildView::sLastInputEventCou
 - (BOOL)isRectObscuredBySubview:(NSRect)inRect;
 
 - (void)processPendingRedraws;
 
 - (void)maybeInitContextMenuTracking;
 
 + (NSEvent*)makeNewCocoaEventWithType:(NSEventType)type fromEvent:(NSEvent*)theEvent;
 
-- (float)beginMaybeResetUnifiedToolbar;
-- (void)endMaybeResetUnifiedToolbar:(float)aOldHeight;
-
 - (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext;
 
 #if USE_CLICK_HOLD_CONTEXTMENU
  // called on a timer two seconds after a mouse down to see if we should display
  // a context menu (click-hold)
 - (void)clickHoldCallback:(id)inEvent;
 #endif
 
@@ -2081,16 +2079,37 @@ void
 nsChildView::DrawOver(LayerManager* aManager, nsIntRect aRect)
 {
   nsCocoaWindow *cocoaWindow = GetXULWindowWidget();
   if (cocoaWindow) {
     cocoaWindow->DrawOver(aManager, aRect);
   }
 }
 
+void
+nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
+{
+  NSWindow* win = [mView window];
+  if (!win || ![win isKindOfClass:[ToolbarWindow class]])
+    return;
+
+  float unifiedToolbarHeight = 0;
+  nsIntRect topPixelStrip(0, 0, [win frame].size.width, 1);
+
+  for (PRUint32 i = 0; i < aThemeGeometries.Length(); ++i) {
+    const ThemeGeometry& g = aThemeGeometries[i];
+    if ((g.mWidgetType == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
+         g.mWidgetType == NS_THEME_TOOLBAR) &&
+        g.mRect.Contains(topPixelStrip)) {
+      unifiedToolbarHeight = g.mRect.YMost();
+    }
+  }
+  [(ToolbarWindow*)win setUnifiedToolbarHeight:unifiedToolbarHeight];
+}
+
 NS_IMETHODIMP
 nsChildView::BeginSecureKeyboardInput()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   nsresult rv = nsBaseWidget::BeginSecureKeyboardInput();
   if (NS_SUCCEEDED(rv))
     ::EnableSecureEventInput();
@@ -2593,65 +2612,40 @@ NSEvent* gLastDragMouseDownEvent = nil;
     }
 
     [mGLContext makeCurrentContext];
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
-// Whenever we paint a toplevel window, we will be notified of any
-// unified toolbar in the window via
-// nsNativeThemeCocoa::RegisterWidgetGeometry. 
-- (float)beginMaybeResetUnifiedToolbar
-{
-  if (![[self window] isKindOfClass:[ToolbarWindow class]] ||
-      [self superview] != [[self window] contentView])
-    return 0.0;
-
-  return [(ToolbarWindow*)[self window] beginMaybeResetUnifiedToolbar];
-}
-
-- (void)endMaybeResetUnifiedToolbar:(float)aOldHeight
-{
-  if (![[self window] isKindOfClass:[ToolbarWindow class]] ||
-      [self superview] != [[self window] contentView])
-    return;
-
-  [(ToolbarWindow*)[self window] endMaybeResetUnifiedToolbar:aOldHeight];
-}
-
 -(void)update
 {
   if (mGLContext) {
     [mGLContext update];
   }
 }
 
 - (void) _surfaceNeedsUpdate:(NSNotification*)notification
 {
    [self update];
 }
 
 // The display system has told us that a portion of our view is dirty. Tell
 // gecko to paint it
 - (void)drawRect:(NSRect)aRect
 {
-  float oldHeight = [self beginMaybeResetUnifiedToolbar];
-
   CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
   [self drawRect:aRect inContext:cgContext];
 
   // If we're a transparent window and our contents have changed, we need
   // to make sure the shadow is updated to the new contents.
   if ([[self window] isKindOfClass:[BaseWindow class]]) {
     [(BaseWindow*)[self window] deferredInvalidateShadow];
   }
-
-  [self endMaybeResetUnifiedToolbar:oldHeight];
 }
 
 - (void)drawRect:(NSRect)aRect inTitlebarContext:(CGContextRef)aContext
 {
   if (!mGeckoChild)
     return;
 
   // Title bar drawing only works if we really draw into aContext, which only
--- a/widget/src/cocoa/nsCocoaWindow.h
+++ b/widget/src/cocoa/nsCocoaWindow.h
@@ -178,25 +178,22 @@ struct UnifiedGradientInfo {
 
 @end
 
 // NSWindow subclass for handling windows with toolbars.
 @interface ToolbarWindow : BaseWindow
 {
   TitlebarAndBackgroundColor *mColor;
   float mUnifiedToolbarHeight;
-  BOOL mInUnifiedToolbarReset;
   NSColor *mBackgroundColor;
 }
 // Pass nil here to get the default appearance.
 - (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive;
-- (void)notifyToolbarAt:(float)aY height:(float)aHeight;
+- (void)setUnifiedToolbarHeight:(float)aHeight;
 - (float)unifiedToolbarHeight;
-- (float)beginMaybeResetUnifiedToolbar;
-- (void)endMaybeResetUnifiedToolbar:(float)aOldHeight;
 - (float)titlebarHeight;
 - (NSRect)titlebarRect;
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect sync:(BOOL)aSync;
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect;
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
 @end
 
 class nsCocoaWindow : public nsBaseWidget, public nsPIWidgetCocoa
--- a/widget/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -2188,25 +2188,25 @@ static const NSString* kStateShowsToolba
 // 4) Whenever the window's main state changes and when [window display] is called,
 //    Cocoa redraws the titlebar using the patternDraw callback function.
 //
 // This class also provides us with a pill button to show/hide the toolbar.
 //
 // Drawing the unified gradient in the titlebar and the toolbar works like this:
 // 1) In the style sheet we set the toolbar's -moz-appearance to -moz-mac-unified-toolbar.
 // 2) When the toolbar is visible and we paint the application chrome
-//    window in nsChildView::drawRect, Gecko calls
-//    nsNativeThemeCocoa::RegisterWidgetGeometry for the widget type
+//    window, the array that Gecko passes nsChildView::UpdateThemeGeometries
+//    will contain an entry for the widget type NS_THEME_TOOLBAR or
 //    NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR.
-// 3) This finds the toolbar frame's ToolbarWindow and passes the toolbar
-//    frame's height to setUnifiedToolbarHeight.
-// 4) If the toolbar height has changed, a titlebar redraw is triggered by
-//    [self display] and the upper part of the unified gradient is drawn in the
-//    titlebar.
-// 5) DrawUnifiedToolbar draws the lower part of the unified gradient in the toolbar.
+// 3) nsChildView::UpdateThemeGeometries finds the toolbar frame's ToolbarWindow
+//    and passes the toolbar frame's height to setUnifiedToolbarHeight.
+// 4) If the toolbar height has changed, a titlebar redraw is triggered and the
+//    upper part of the unified gradient is drawn in the titlebar.
+// 5) The lower part of the unified gradient in the toolbar is drawn during
+//    normal window content painting in nsNativeThemeCocoa::DrawUnifiedToolbar.
 //
 // Whenever the unified gradient is drawn in the titlebar or the toolbar, both
 // titlebar height and toolbar height must be known in order to construct the
 // correct gradient (which is a linear gradient with the length
 // titlebarHeight + toolbarHeight - 1). But you can only get from the toolbar frame
 // to the containing window - the other direction doesn't work. That's why the
 // toolbar height is cached in the ToolbarWindow but nsNativeThemeCocoa can simply
 // query the window for its titlebar height when drawing the toolbar.
@@ -2219,17 +2219,16 @@ static const NSString* kStateShowsToolba
   aStyle = aStyle | NSTexturedBackgroundWindowMask;
   if ((self = [super initWithContentRect:aContentRect styleMask:aStyle backing:aBufferingType defer:aFlag])) {
     mColor = [[TitlebarAndBackgroundColor alloc] initWithWindow:self];
     // Bypass our guard method below.
     [super setBackgroundColor:mColor];
     mBackgroundColor = [NSColor whiteColor];
 
     mUnifiedToolbarHeight = 0.0f;
-    mInUnifiedToolbarReset = NO;
 
     // setBottomCornerRounded: is a private API call, so we check to make sure
     // we respond to it just in case.
     if ([self respondsToSelector:@selector(setBottomCornerRounded:)])
       [self setBottomCornerRounded:NO];
 
     [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
     [self setContentBorderThickness:0.0f forEdge:NSMaxYEdge];
@@ -2263,30 +2262,16 @@ static const NSString* kStateShowsToolba
   mBackgroundColor = aColor;
 }
 
 - (NSColor*)windowBackgroundColor
 {
   return mBackgroundColor;
 }
 
-// This is called by nsNativeThemeCocoa.mm's RegisterWidgetGeometry.
-// We need to know the toolbar's height in order to draw the correct
-// unified gradient in the titlebar.
-- (void)notifyToolbarAt:(float)aY height:(float)aHeight
-{
-  // Ignore unexpected notifications about the toolbar height
-  if (!mInUnifiedToolbarReset)
-    return;
-
-  if (aY <= 0.0 && aY + aHeight > mUnifiedToolbarHeight) {
-    mUnifiedToolbarHeight = aY + aHeight;
-  }
-}
-
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect
 {
   [self setTitlebarNeedsDisplayInRect:aRect sync:NO];
 }
 
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect sync:(BOOL)aSync
 {
   NSRect titlebarRect = [self titlebarRect];
@@ -2317,37 +2302,30 @@ static const NSString* kStateShowsToolba
 }
 
 - (float)titlebarHeight
 {
   NSRect frameRect = [self frame];
   return frameRect.size.height - [self contentRectForFrameRect:frameRect].size.height;
 }
 
-- (float)beginMaybeResetUnifiedToolbar
-{
-  mInUnifiedToolbarReset = YES;
-  float old = mUnifiedToolbarHeight;
-  mUnifiedToolbarHeight = 0.0;
-  return old;
-}
-
-- (void)endMaybeResetUnifiedToolbar:(float)aOldHeight
+- (void)setUnifiedToolbarHeight:(float)aHeight
 {
-  if (mInUnifiedToolbarReset) {
-    mInUnifiedToolbarReset = NO;
-    if (mUnifiedToolbarHeight == aOldHeight)
-      return;
-
-    [self setContentBorderThickness:mUnifiedToolbarHeight forEdge:NSMaxYEdge];
-
-    // Since this function is only called inside painting, the repaint needs to
-    // be synchronous.
-    [self setTitlebarNeedsDisplayInRect:[self titlebarRect] sync:YES];
-  }
+  if ([self drawsContentsIntoWindowFrame] || aHeight == mUnifiedToolbarHeight)
+    return;
+
+  mUnifiedToolbarHeight = aHeight;
+
+  // Update sheet positioning hint.
+  [self setContentBorderThickness:mUnifiedToolbarHeight forEdge:NSMaxYEdge];
+
+  // Redraw the title bar. If we're inside painting, we'll do it right now,
+  // otherwise we'll just invalidate it.
+  BOOL needSyncRedraw = ([NSView focusView] != nil);
+  [self setTitlebarNeedsDisplayInRect:[self titlebarRect] sync:needSyncRedraw];
 }
 
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState
 {
   BOOL stateChanged = ([self drawsContentsIntoWindowFrame] != aState);
   [super setDrawsContentsIntoWindowFrame:aState];
   if (stateChanged && [[self delegate] isKindOfClass:[WindowDelegate class]]) {
     WindowDelegate *windowDelegate = (WindowDelegate *)[self delegate];
--- a/widget/src/cocoa/nsNativeThemeCocoa.h
+++ b/widget/src/cocoa/nsNativeThemeCocoa.h
@@ -62,19 +62,16 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // The nsITheme interface.
   NS_IMETHOD DrawWidgetBackground(nsIRenderingContext* aContext,
                                   nsIFrame* aFrame,
                                   PRUint8 aWidgetType,
                                   const nsRect& aRect,
                                   const nsRect& aDirtyRect);
-  virtual void RegisterWidgetGeometry(nsIWidget* aWindow,
-                                      PRUint8 aWidgetType,
-                                      const nsIntRect& aRect);
   NS_IMETHOD GetWidgetBorder(nsIDeviceContext* aContext, 
                              nsIFrame* aFrame,
                              PRUint8 aWidgetType,
                              nsIntMargin* aResult);
 
   virtual PRBool GetWidgetPadding(nsIDeviceContext* aContext,
                                   nsIFrame* aFrame,
                                   PRUint8 aWidgetType,
--- a/widget/src/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/src/cocoa/nsNativeThemeCocoa.mm
@@ -1514,35 +1514,16 @@ nsNativeThemeCocoa::DrawResizer(CGContex
   drawInfo.size = kHIThemeGrowBoxSizeNormal;
 
   RenderTransformedHIThemeControl(cgContext, aRect, RenderResizer, &drawInfo,
                                   IsFrameRTL(aFrame));
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
-static PRBool
-IsWindowSpanningToolbar(nsIWidget* aWindow,
-                        PRUint8 aWidgetType,
-                        const nsIntRect& aRect,
-                        ToolbarWindow** aCocoaWindow)
-{
-  nsIWidget* topLevelWidget = aWindow->GetTopLevelWidget();
-  if (!topLevelWidget)
-    return PR_FALSE;
-  NSWindow* win = (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
-  if (!win || ![win isKindOfClass:[ToolbarWindow class]])
-    return PR_FALSE;
-
-  *aCocoaWindow = (ToolbarWindow*)win;
-  return (aWidgetType == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
-          aWidgetType == NS_THEME_TOOLBAR) &&
-         aRect.x == 0 && aRect.width == [win frame].size.width;
-}
-
 NS_IMETHODIMP
 nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame,
                                          PRUint8 aWidgetType, const nsRect& aRect,
                                          const nsRect& aDirtyRect)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   // setup to draw into the correct port
@@ -1977,28 +1958,16 @@ nsNativeThemeCocoa::DrawWidgetBackground
 
   nativeDrawing.EndNativeDrawing();
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
-void
-nsNativeThemeCocoa::RegisterWidgetGeometry(nsIWidget* aWindow,
-                                           PRUint8 aWidgetType,
-                                           const nsIntRect& aRect)
-{
-  ToolbarWindow* cocoaWindow;
-  if (IsWindowSpanningToolbar(aWindow, aWidgetType, aRect, &cocoaWindow) &&
-      ![cocoaWindow drawsContentsIntoWindowFrame]) {
-    [cocoaWindow notifyToolbarAt:aRect.y height:aRect.height];
-  }
-}
-                                         
 nsIntMargin
 nsNativeThemeCocoa::RTLAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame)
 {
   if (IsFrameRTL(aFrame))
     return nsIntMargin(aMargin.right, aMargin.top, aMargin.left, aMargin.bottom);
 
   return aMargin;
 }
--- a/widget/src/xpwidgets/nsBaseWidget.h
+++ b/widget/src/xpwidgets/nsBaseWidget.h
@@ -114,16 +114,17 @@ public:
   NS_IMETHOD              HideWindowChrome(PRBool aShouldHide);
   NS_IMETHOD              MakeFullScreen(PRBool aFullScreen);
   virtual nsIDeviceContext* GetDeviceContext();
   virtual nsIToolkit*     GetToolkit();
   virtual LayerManager*   GetLayerManager(bool *aAllowRetaining = nsnull);
   virtual LayerManager*   GetLayerManager(LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nsnull);
   virtual void            DrawOver(LayerManager* aManager, nsIntRect aRect) {}
+  virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}
   virtual gfxASurface*    GetThebesSurface();
   NS_IMETHOD              SetModal(PRBool aModal); 
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType);
   NS_IMETHOD              SetBounds(const nsIntRect &aRect);
   NS_IMETHOD              GetBounds(nsIntRect &aRect);
   NS_IMETHOD              GetClientBounds(nsIntRect &aRect);
   NS_IMETHOD              GetScreenBounds(nsIntRect &aRect);
   virtual nsIntPoint      GetClientOffset();