Bug 658005. Part 2. Add a frame visibility API that takes into account everything we need, and use it. r=roc
authorTimothy Nikkel <tnikkel@gmail.com>
Wed, 26 Oct 2011 18:57:55 -0500
changeset 79259 bd1754632d8caa8ec12c32b2b52c2d5712648517
parent 79258 25e0254f4bda4064cbdaabdcc6bb15b8ee309b68
child 79260 6eda7e1b72258c6fdffb1850b8aa3ae13cb0aa65
push id2938
push usertnikkel@gmail.com
push dateWed, 26 Oct 2011 23:59:21 +0000
treeherdermozilla-inbound@90c31d55b8b5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs658005
milestone10.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 658005. Part 2. Add a frame visibility API that takes into account everything we need, and use it. r=roc
content/events/src/nsEventStateManager.cpp
content/xul/content/src/nsXULElement.cpp
docshell/base/nsDocShell.cpp
dom/base/nsFocusManager.cpp
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/xul/base/src/nsDeckFrame.cpp
layout/xul/base/src/nsDeckFrame.h
view/public/nsIViewObserver.h
view/src/nsViewManager.cpp
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1437,20 +1437,17 @@ IsAccessKeyTarget(nsIContent* aContent, 
 
     // For XUL we do visibility checks.
   if (!aFrame)
     return false;
 
   if (aFrame->IsFocusable())
     return true;
 
-  if (!aFrame->GetStyleVisibility()->IsVisible())
-    return false;
-
-  if (!aFrame->AreAncestorViewsVisible())
+  if (!aFrame->IsVisibleConsideringAncestors())
     return false;
 
   // XUL controls can be activated.
   nsCOMPtr<nsIDOMXULControlElement> control(do_QueryInterface(aContent));
   if (control)
     return true;
 
   if (aContent->IsHTML()) {
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -651,24 +651,17 @@ nsXULElement::PerformAccesskey(bool aKey
         // |element|, or clear it.
         content = do_QueryInterface(element);
 
         if (!content)
             return;
     }
 
     nsIFrame* frame = content->GetPrimaryFrame();
-    if (!frame)
-        return;
-
-    const nsStyleVisibility* vis = frame->GetStyleVisibility();
-
-    if (vis->mVisible == NS_STYLE_VISIBILITY_COLLAPSE ||
-        vis->mVisible == NS_STYLE_VISIBILITY_HIDDEN ||
-        !frame->AreAncestorViewsVisible())
+    if (!frame || !frame->IsVisibleConsideringAncestors())
         return;
 
     nsXULElement* elm = FromContent(content);
     if (elm) {
         // Define behavior for each type of XUL element.
         nsIAtom *tag = content->Tag();
         if (tag != nsGkAtoms::toolbarbutton) {
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4816,18 +4816,21 @@ nsDocShell::GetVisibility(bool * aVisibi
 
         nsIContent *shellContent =
             pPresShell->GetDocument()->FindContentForSubDocument(presShell->GetDocument());
         NS_ASSERTION(shellContent, "subshell not in the map");
 
         nsIFrame* frame = shellContent ? shellContent->GetPrimaryFrame() : nsnull;
         bool isDocShellOffScreen = false;
         docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
-        if (frame && !frame->AreAncestorViewsVisible() && !isDocShellOffScreen)
+        if (frame &&
+            !frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
+            !isDocShellOffScreen) {
             return NS_OK;
+        }
 
         treeItem = parentItem;
         treeItem->GetParent(getter_AddRefs(parentItem));
     }
 
     nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
     if (!treeOwnerAsWin) {
         *aVisibility = true;
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1437,18 +1437,17 @@ nsFocusManager::CheckIfFocusable(nsICont
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (!frame)
     return nsnull;
 
   if (aContent->Tag() == nsGkAtoms::area && aContent->IsHTML()) {
     // HTML areas do not have their own frame, and the img frame we get from
     // GetPrimaryFrame() is not relevant as to whether it is focusable or
     // not, so we have to do all the relevant checks manually for them.
-    return frame->AreAncestorViewsVisible() &&
-           frame->GetStyleVisibility()->IsVisible() &&
+    return frame->IsVisibleConsideringAncestors() &&
            aContent->IsFocusable() ? aContent : nsnull;
   }
 
   // if this is a child frame content node, check if it is visible and
   // call the content node's IsFocusable method instead of the frame's
   // IsFocusable method. This skips checking the style system and ensures that
   // offscreen browsers can still be focused.
   nsIDocument* subdoc = doc->GetSubDocumentFor(aContent);
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5246,18 +5246,21 @@ void PresShell::SynthesizeMouseMove(bool
  */
 static nsIView* FindFloatingViewContaining(nsIView* aView, nsPoint aPt)
 {
   if (aView->GetVisibility() == nsViewVisibility_kHide)
     // No need to look into descendants.
     return nsnull;
 
   nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
-  if (frame && !frame->PresContext()->PresShell()->IsActive()) {
-    return nsnull;
+  if (frame) {
+    if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
+        !frame->PresContext()->PresShell()->IsActive()) {
+      return nsnull;
+    }
   }
 
   for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
     nsIView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt));
     if (r)
       return r;
   }
 
@@ -5280,18 +5283,21 @@ static nsIView* FindFloatingViewContaini
 static nsIView* FindViewContaining(nsIView* aView, nsPoint aPt)
 {
   if (!aView->GetDimensions().Contains(aPt) ||
       aView->GetVisibility() == nsViewVisibility_kHide) {
     return nsnull;
   }
 
   nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
-  if (frame && !frame->PresContext()->PresShell()->IsActive()) {
-    return nsnull;
+  if (frame) {
+    if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) ||
+        !frame->PresContext()->PresShell()->IsActive()) {
+      return nsnull;
+    }
   }
 
   for (nsIView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
     nsIView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt));
     if (r)
       return r;
   }
 
@@ -6859,17 +6865,17 @@ PresShell::ShouldIgnoreInvalidation()
   return mPaintingSuppressed || !mIsActive;
 }
 
 NS_IMETHODIMP_(void)
 PresShell::WillPaint(bool aWillSendDidPaint)
 {
   // Don't bother doing anything if some viewmanager in our tree is painting
   // while we still have painting suppressed or we are not active.
-  if (mPaintingSuppressed || !mIsActive) {
+  if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
     return;
   }
 
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
   if (!rootPresContext) {
     return;
   }
 
@@ -6885,29 +6891,56 @@ PresShell::WillPaint(bool aWillSendDidPa
   // interruptible; if we can't do all the reflows it's better to flicker a bit
   // than to freeze up.
   FlushPendingNotifications(Flush_InterruptibleLayout);
 }
 
 NS_IMETHODIMP_(void)
 PresShell::DidPaint()
 {
-  if (mPaintingSuppressed || !mIsActive) {
+  if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
     return;
   }
 
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
   if (!rootPresContext) {
     return;
   }
   if (rootPresContext == mPresContext) {
     rootPresContext->UpdatePluginGeometry();
   }
 }
 
+NS_IMETHODIMP_(bool)
+PresShell::IsVisible()
+{
+  if (!mViewManager)
+    return false;
+
+  nsIView* view = mViewManager->GetRootView();
+  if (!view)
+    return true;
+
+  // inner view of subdoc frame
+  view = view->GetParent();
+  if (!view)
+    return true;
+  
+  // subdoc view
+  view = view->GetParent();
+  if (!view)
+    return true;
+
+  nsIFrame* frame = static_cast<nsIFrame*>(view->GetClientData());
+  if (!frame)
+    return true;
+
+  return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY);
+}
+
 nsresult
 PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets)
 {
   aSheets.Clear();
   PRInt32 sheetCount = mStyleSet->SheetCount(nsStyleSet::eAgentSheet);
 
   for (PRInt32 i = 0; i < sheetCount; ++i) {
     nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(nsStyleSet::eAgentSheet, i);
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -332,16 +332,17 @@ public:
                                                         nsEventStatus* aStatus);
   NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
   NS_IMETHOD_(bool) ShouldIgnoreInvalidation();
   NS_IMETHOD_(void) WillPaint(bool aWillSendDidPaint);
   NS_IMETHOD_(void) DidPaint();
   NS_IMETHOD_(void) DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                            bool aFlushOnHoverChange);
   NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView);
+  NS_IMETHOD_(bool) IsVisible();
 
   // caret handling
   virtual NS_HIDDEN_(already_AddRefed<nsCaret>) GetCaret() const;
   virtual NS_HIDDEN_(void) MaybeInvalidateCaretPosition();
   NS_IMETHOD SetCaretEnabled(bool aInEnable);
   NS_IMETHOD SetCaretReadOnly(bool aReadOnly);
   NS_IMETHOD GetCaretEnabled(bool *aOutEnabled);
   NS_IMETHOD SetCaretVisibilityDuringSelection(bool aVisibility);
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -114,16 +114,17 @@
 #include "nsBoxLayoutState.h"
 #include "nsBlockFrame.h"
 #include "nsDisplayList.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsExpirationTracker.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGEffects.h"
 #include "nsChangeHint.h"
+#include "nsDeckFrame.h"
 
 #include "gfxContext.h"
 #include "CSSCalc.h"
 #include "nsAbsoluteContainingBlock.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 
@@ -296,16 +297,58 @@ nsIFrame::CheckAndClearPaintedState()
       if (child->CheckAndClearPaintedState()) {
         result = true;
       }
     }
   }
   return result;
 }
 
+bool
+nsIFrame::IsVisibleConsideringAncestors(PRUint32 aFlags) const
+{
+  if (!GetStyleVisibility()->IsVisible()) {
+    return false;
+  }
+
+  const nsIFrame* frame = this;
+  while (frame) {
+    nsIView* view = frame->GetView();
+    if (view && view->GetVisibility() == nsViewVisibility_kHide)
+      return false;
+    
+    nsIFrame* parent = frame->GetParent();
+    nsDeckFrame* deck = do_QueryFrame(parent);
+    if (deck) {
+      if (deck->GetSelectedBox() != frame)
+        return false;
+    }
+
+    if (parent) {
+      frame = parent;
+    } else {
+      parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
+      if (!parent)
+        break;
+
+      if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
+          parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
+        break;
+      }
+
+      if (!parent->GetStyleVisibility()->IsVisible())
+        return false;
+
+      frame = parent;
+    }
+  }
+
+  return true;
+}
+
 static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
                                     const nsIFrame* aFrame,
                                     const nsStyleDisplay* aDisp, 
                                     nsRect* aRect);
 
 static bool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
                                   const nsStyleDisplay* aDisp, 
                                   const nsIFrame* aFrame,
@@ -7000,48 +7043,44 @@ nsFrame::GetStyleDataExternal(nsStyleStr
 nsIFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
 {
   PRInt32 tabIndex = -1;
   if (aTabIndex) {
     *aTabIndex = -1; // Default for early return is not focusable
   }
   bool isFocusable = false;
 
-  if (mContent && mContent->IsElement() && AreAncestorViewsVisible()) {
-    const nsStyleVisibility* vis = GetStyleVisibility();
-    if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
-        vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) {
-      const nsStyleUserInterface* ui = GetStyleUserInterface();
-      if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
-          ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
-        // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
-        tabIndex = 0;
-      }
-      isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
-      if (!isFocusable && !aWithMouse &&
-          GetType() == nsGkAtoms::scrollFrame &&
-          mContent->IsHTML() &&
-          !mContent->IsRootOfNativeAnonymousSubtree() &&
-          mContent->GetParent() &&
-          !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
-        // Elements with scrollable view are focusable with script & tabbable
-        // Otherwise you couldn't scroll them with keyboard, which is
-        // an accessibility issue (e.g. Section 508 rules)
-        // However, we don't make them to be focusable with the mouse,
-        // because the extra focus outlines are considered unnecessarily ugly.
-        // When clicked on, the selection position within the element 
-        // will be enough to make them keyboard scrollable.
-        nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
-        if (scrollFrame &&
-            scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
-            !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
-            // Scroll bars will be used for overflow
-            isFocusable = true;
-            tabIndex = 0;
-        }
+  if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors()) {
+    const nsStyleUserInterface* ui = GetStyleUserInterface();
+    if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
+        ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
+      // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
+      tabIndex = 0;
+    }
+    isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
+    if (!isFocusable && !aWithMouse &&
+        GetType() == nsGkAtoms::scrollFrame &&
+        mContent->IsHTML() &&
+        !mContent->IsRootOfNativeAnonymousSubtree() &&
+        mContent->GetParent() &&
+        !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
+      // Elements with scrollable view are focusable with script & tabbable
+      // Otherwise you couldn't scroll them with keyboard, which is
+      // an accessibility issue (e.g. Section 508 rules)
+      // However, we don't make them to be focusable with the mouse,
+      // because the extra focus outlines are considered unnecessarily ugly.
+      // When clicked on, the selection position within the element 
+      // will be enough to make them keyboard scrollable.
+      nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
+      if (scrollFrame &&
+          scrollFrame->GetScrollbarStyles() != nsIScrollableFrame::ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) &&
+          !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
+          // Scroll bars will be used for overflow
+          isFocusable = true;
+          tabIndex = 0;
       }
     }
   }
 
   if (aTabIndex) {
     *aTabIndex = tabIndex;
   }
   return isFocusable;
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2755,16 +2755,29 @@ NS_PTR_TO_INT32(frame->Properties().Get(
   virtual void MarkAsAbsoluteContainingBlock();
   // Child frame types override this function to select their own child list name
   virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kAbsoluteList; }
 
   // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set, and
   // clears this bit if so.
   bool CheckAndClearPaintedState();
 
+  // CSS visibility just doesn't cut it because it doesn't inherit through
+  // documents. Also if this frame is in a hidden card of a deck then it isn't
+  // visible either and that isn't expressed using CSS visibility. Also if it
+  // is in a hidden view (there are a few cases left and they are hopefully
+  // going away soon).
+  // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
+  // ignore the chrome/content boundary, otherwise we stop looking when we
+  // reach it.
+  enum {
+    VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01
+  };
+  bool IsVisibleConsideringAncestors(PRUint32 aFlags = 0) const;
+
 protected:
   // Members
   nsRect           mRect;
   nsIContent*      mContent;
   nsStyleContext*  mStyleContext;
   nsIFrame*        mParent;
 private:
   nsIFrame*        mNextSibling;  // doubly-linked list of frames
--- a/layout/xul/base/src/nsDeckFrame.cpp
+++ b/layout/xul/base/src/nsDeckFrame.cpp
@@ -212,17 +212,17 @@ nsDeckFrame::GetSelectedIndex()
 
     // convert it to an integer
     index = value.ToInteger(&error);
   }
 
   return index;
 }
 
-nsIBox* 
+nsIFrame* 
 nsDeckFrame::GetSelectedBox()
 {
   return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nsnull; 
 }
 
 NS_IMETHODIMP
 nsDeckFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
--- a/layout/xul/base/src/nsDeckFrame.h
+++ b/layout/xul/base/src/nsDeckFrame.h
@@ -92,20 +92,21 @@ public:
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
       return MakeFrameName(NS_LITERAL_STRING("Deck"), aResult);
   }
 #endif
 
   nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
+  nsIFrame* GetSelectedBox();
+
 protected:
 
   // REVIEW: Sorry, I couldn't resist devirtualizing these.
-  nsIBox* GetSelectedBox();
   void IndexChanged(nsPresContext* aPresContext);
   PRInt32 GetSelectedIndex();
   void HideBox(nsPresContext* aPresContext, nsIBox* aBox);
   void ShowBox(nsPresContext* aPresContext, nsIBox* aBox);
 
 private:
 
   PRInt32 mIndex;
--- a/view/public/nsIViewObserver.h
+++ b/view/public/nsIViewObserver.h
@@ -45,18 +45,18 @@
 
 class nsRenderingContext;
 class nsGUIEvent;
 class nsIWidget;
 class nsRegion;
 class nsIntRegion;
 
 #define NS_IVIEWOBSERVER_IID  \
-  { 0xdc283a18, 0x61cb, 0x468c, \
-    { 0x8d, 0xb8, 0x9b, 0x81, 0xf7, 0xc9, 0x33, 0x25 } }
+  { 0xac6eec35, 0x65d2, 0x4fe8, \
+    { 0xa1, 0x37, 0x1a, 0xc3, 0xf6, 0x51, 0x52, 0x56 } }
 
 class nsIViewObserver : public nsISupports
 {
 public:
   
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IVIEWOBSERVER_IID)
 
   /* called when the observer needs to paint. This paints the entire
@@ -140,13 +140,18 @@ public:
                                            bool aFlushOnHoverChange) = 0;
 
   /**
    * If something within aView is capturing the mouse, clear the capture.
    * if aView is null, clear the mouse capture no matter what is capturing it.
    */
   NS_IMETHOD_(void) ClearMouseCapture(nsIView* aView) = 0;
 
+  /**
+   * Returns true if the view observer is visible in some way. Otherwise false.
+   */
+  NS_IMETHOD_(bool) IsVisible() = 0;
+
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewObserver, NS_IVIEWOBSERVER_IID)
 
 #endif
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -260,17 +260,17 @@ void nsViewManager::DoSetWindowDimension
     if (mObserver)
       mObserver->ResizeReflow(mRootView, aWidth, aHeight);
   }
 }
 
 NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
 {
   if (mRootView) {
-    if (mRootView->IsEffectivelyVisible()) {
+    if (mRootView->IsEffectivelyVisible() && mObserver && mObserver->IsVisible()) {
       if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
           mDelayedResize != nsSize(aWidth, aHeight)) {
         // We have a delayed resize; that now obsolete size may already have
         // been flushed to the PresContext so we need to update the PresContext
         // with the new size because if the new size is exactly the same as the
         // root view's current size then DoSetWindowDimensions will not
         // request a resize reflow (which would correct it). See bug 617076.
         mDelayedResize = nsSize(aWidth, aHeight);
@@ -822,17 +822,18 @@ NS_IMETHODIMP nsViewManager::DispatchEve
           // If an ancestor widget was hidden and then shown, we could
           // have a delayed resize to handle.
           bool didResize = false;
           for (nsViewManager *vm = this; vm;
                vm = vm->mRootView->GetParent()
                       ? vm->mRootView->GetParent()->GetViewManager()
                       : nsnull) {
             if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-                vm->mRootView->IsEffectivelyVisible()) {
+                vm->mRootView->IsEffectivelyVisible() &&
+                mObserver && mObserver->IsVisible()) {
               vm->FlushDelayedResize(true);
 
               // Paint later.
               vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC);
               didResize = true;
 
               // not sure if it's valid for us to claim that we
               // ignored this, but we're going to do so anyway, since