Bug 972566, when a window is resized, panels should be repositioned after the view reflow rather than within the webshell listener, r=tn, a=lsblakk.
authorNeil Deakin <neil@mozilla.com>
Wed, 19 Mar 2014 12:48:08 -0400
changeset 183658 1a92004a684f
parent 183651 26f9d2df24af
child 183659 85d2c5b844bc
push id3439
push usermconley@mozilla.com
push date2014-04-08 14:42 +0000
Treeherderresults
reviewerstn, lsblakk
bugs972566
milestone29.0
Bug 972566, when a window is resized, panels should be repositioned after the view reflow rather than within the webshell listener, r=tn, a=lsblakk.
layout/xul/nsXULPopupManager.cpp
layout/xul/nsXULPopupManager.h
view/src/nsView.cpp
xpfe/appshell/src/nsWebShellWindow.cpp
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -323,39 +323,54 @@ nsXULPopupManager::GetRollupWidget()
 }
 
 void
 nsXULPopupManager::AdjustPopupsOnWindowChange(nsPIDOMWindow* aWindow)
 {
   // When the parent window is moved, adjust any child popups. Dismissable
   // menus and panels are expected to roll up when a window is moved, so there
   // is no need to check these popups, only the noautohide popups.
+
+  // The items are added to a list so that they can be adjusted bottom to top.
+  nsTArray<nsMenuPopupFrame *> list;
+
   nsMenuChainItem* item = mNoHidePanels;
   while (item) {
     // only move popups that are within the same window and where auto
     // positioning has not been disabled
-    nsMenuPopupFrame* frame= item->Frame();
+    nsMenuPopupFrame* frame = item->Frame();
     if (frame->GetAutoPosition()) {
       nsIContent* popup = frame->GetContent();
       if (popup) {
         nsIDocument* document = popup->GetCurrentDoc();
         if (document) {
           nsPIDOMWindow* window = document->GetWindow();
           if (window) {
             window = window->GetPrivateRoot();
             if (window == aWindow) {
-              frame->SetPopupPosition(nullptr, true, false);
+              list.AppendElement(frame);
             }
           }
         }
       }
     }
 
     item = item->GetParent();
   }
+
+  for (int32_t l = list.Length() - 1; l >= 0; l--) {
+    list[l]->SetPopupPosition(nullptr, true, false);
+  }
+}
+
+void nsXULPopupManager::AdjustPopupsOnWindowChange(nsIPresShell* aPresShell)
+{
+  if (aPresShell->GetDocument()) {
+    AdjustPopupsOnWindowChange(aPresShell->GetDocument()->GetWindow());
+  }
 }
 
 static
 nsMenuPopupFrame* GetPopupToMoveOrResize(nsIFrame* aFrame)
 {
   nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(aFrame);
   if (!menuPopupFrame)
     return nullptr;
--- a/layout/xul/nsXULPopupManager.h
+++ b/layout/xul/nsXULPopupManager.h
@@ -295,17 +295,20 @@ public:
   // initialize and shutdown methods called by nsLayoutStatics
   static nsresult Init();
   static void Shutdown();
 
   // returns a weak reference to the popup manager instance, could return null
   // if a popup manager could not be allocated
   static nsXULPopupManager* GetInstance();
 
+  // This should be called when a window is moved or resized to adjust the
+  // popups accordingly.
   void AdjustPopupsOnWindowChange(nsPIDOMWindow* aWindow);
+  void AdjustPopupsOnWindowChange(nsIPresShell* aPresShell);
 
   // given a menu frame, find the prevous or next menu frame. If aPopup is
   // true then navigate a menupopup, from one item on the menu to the previous
   // or next one. This is used for cursor navigation between items in a popup
   // menu. If aIsPopup is false, the navigation is on a menubar, so navigate
   // between menus on the menubar. This is used for left/right cursor navigation.
   //
   // Items that are not valid, such as non-menu or non-menuitem elements are
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -997,16 +997,25 @@ nsView::WindowResized(nsIWidget* aWidget
   if (this == mViewManager->GetRootView()) {
     nsRefPtr<nsDeviceContext> devContext = mViewManager->GetDeviceContext();
     // ensure DPI is up-to-date, in case of window being opened and sized
     // on a non-default-dpi display (bug 829963)
     devContext->CheckDPIChange();
     int32_t p2a = devContext->AppUnitsPerDevPixel();
     mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(aWidth, p2a),
                                       NSIntPixelsToAppUnits(aHeight, p2a));
+
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm) {
+      nsIPresShell* presShell = mViewManager->GetPresShell();
+      if (presShell && presShell->GetDocument()) {
+        pm->AdjustPopupsOnWindowChange(presShell);
+      }
+    }
+
     return true;
   }
   else if (IsPopupWidget(aWidget)) {
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm) {
       pm->PopupResized(mFrame, nsIntSize(aWidth, aHeight));
       return true;
     }
--- a/xpfe/appshell/src/nsWebShellWindow.cpp
+++ b/xpfe/appshell/src/nsWebShellWindow.cpp
@@ -265,22 +265,16 @@ nsWebShellWindow::WindowMoved(nsIWidget*
   // repeated move events as the user drags the window
   SetPersistenceTimer(PAD_POSITION);
   return false;
 }
 
 bool
 nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
 {
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm) {
-    nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
-    pm->AdjustPopupsOnWindowChange(window);
-  }
-
   nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
   if (shellAsWin) {
     shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false);
   }
   // Persist size, but not immediately, in case this OS is firing
   // repeated size events as the user drags the sizing handle
   if (!IsLocked())
     SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);