Backed out changeset c353fe809be0
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 30 Jul 2009 22:06:02 +1200
changeset 30897 4834ae129387eaeb8c30274bd45ca17399a35530
parent 30877 c353fe809be05e922e2d6146eb8e07cf4cfd79dd
child 30898 36a36a9c942bbd1c720968f154d162d207a0ed8c
push idunknown
push userunknown
push dateunknown
milestone1.9.2a1pre
backs outc353fe809be05e922e2d6146eb8e07cf4cfd79dd
Backed out changeset c353fe809be0
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/xul/base/src/nsBoxFrame.cpp
layout/xul/base/src/nsDeckFrame.h
layout/xul/base/src/nsLeafBoxFrame.cpp
view/public/nsIViewManager.h
view/src/nsView.cpp
view/src/nsView.h
view/src/nsViewManager.cpp
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -612,20 +612,21 @@ nsContainerFrame::SyncFrameViewPropertie
 
   // Make sure visibility is correct
   if (0 == (aFlags & NS_FRAME_NO_VISIBILITY)) {
     // See if the view should be hidden or visible
     PRBool  viewIsVisible = PR_TRUE;
 
     if (!aStyleContext->GetStyleVisibility()->IsVisible() &&
         !aFrame->SupportsVisibilityHidden()) {
-      // If it's a subdocument frame or a plugin, hide the view and
-      // any associated widget.
-      // These are leaf elements so this is OK, no descendant can be
-      // visibility:visible.
+      // If it's a scrollable frame that can't hide its scrollbars,
+      // hide the view. This means that child elements can't override
+      // their parent's visibility, but it's not practical to leave it
+      // visible in all cases because the scrollbars will be showing
+      // XXXldb Does the view system really enforce this correctly?
       viewIsVisible = PR_FALSE;
     } else if (IsMenuPopup(aFrame)) {
       // if the view is for a popup, don't show the view if the popup is closed
       nsIWidget* widget = aView->GetWidget();
       if (widget) {
         nsWindowType windowType;
         widget->GetWindowType(windowType);
         if (windowType == eWindowType_popup) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -6712,16 +6712,25 @@ nsFrame::SetParent(const nsIFrame* aPare
 {
   PRBool wasBoxWrapped = IsBoxWrapped();
   nsIFrame::SetParent(aParent);
   if (!wasBoxWrapped && IsBoxWrapped())
     InitBoxMetrics(PR_TRUE);
   else if (wasBoxWrapped && !IsBoxWrapped())
     DeleteProperty(nsGkAtoms::boxMetricsProperty);
 
+  if (aParent && aParent->IsBoxFrame()) {
+    if (aParent->ChildrenMustHaveWidgets()) {
+        nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE);
+        nsIView* view = GetView();
+        if (!view->HasWidget())
+          CreateWidgetForView(view);
+    }
+  }
+
   return NS_OK;
 }
 
 static void
 DeleteBoxMetrics(void    *aObject,
                  nsIAtom *aPropertyName,
                  void    *aPropertyValue,
                  void    *aData)
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -102,19 +102,20 @@ struct nsPeekOffsetStruct;
 struct nsPoint;
 struct nsRect;
 struct nsSize;
 struct nsMargin;
 
 typedef class nsIFrame nsIBox;
 
 // IID for the nsIFrame interface
+// 7b437d20-a34e-11dd-ad8b-0800200c9a66
 #define NS_IFRAME_IID \
-  { 0x7e9018b5, 0x5405, 0x4e2b, \
-    { 0x87, 0x67, 0xe2, 0xb4, 0xb1, 0x3e, 0xc1, 0x69 } }
+  { 0x7b437d20, 0xa34e, 0x11dd, \
+    { 0xad, 0x8b, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
 
 /**
  * Indication of how the frame can be split. This is used when doing runaround
  * of floats, and when pulling up child frames from a next-in-flow.
  *
  * The choices are splittable, not splittable at all, and splittable in
  * a non-rectangular fashion. This last type only applies to block-level
  * elements, and indicates whether splitting can be used when doing runaround.
@@ -2280,16 +2281,19 @@ NS_PTR_TO_INT32(frame->GetProperty(nsGkA
 
 #ifdef DEBUG_LAYOUT
   NS_IMETHOD SetDebug(nsBoxLayoutState& aState, PRBool aDebug)=0;
   NS_IMETHOD GetDebug(PRBool& aDebug)=0;
 
   NS_IMETHOD DumpBox(FILE* out)=0;
 #endif
 
+  // Only nsDeckFrame requires that all its children have widgets
+  virtual PRBool ChildrenMustHaveWidgets() const { return PR_FALSE; }
+
   /**
    * @return PR_TRUE if this text frame ends with a newline character.  It
    * should return PR_FALSE if this is not a text frame.
    */
   virtual PRBool HasTerminalNewline() const;
 
   static PRBool AddCSSPrefSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize);
   static PRBool AddCSSMinSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize);
--- a/layout/xul/base/src/nsBoxFrame.cpp
+++ b/layout/xul/base/src/nsBoxFrame.cpp
@@ -200,16 +200,28 @@ nsBoxFrame::Init(nsIContent*      aConte
                  nsIFrame*        aParent,
                  nsIFrame*        aPrevInFlow)
 {
   nsresult  rv = nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
   NS_ENSURE_SUCCESS(rv, rv);
 
   MarkIntrinsicWidthsDirty();
 
+  // see if we need a widget
+  if (aParent && aParent->IsBoxFrame()) {
+    if (aParent->ChildrenMustHaveWidgets()) {
+        rv = nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        nsIView* view = GetView();
+        if (!view->HasWidget())
+           view->CreateWidget(kWidgetCID);   
+    }
+  }
+
   CacheAttributes();
 
 #ifdef DEBUG_LAYOUT
     // if we are root and this
   if (mState & NS_STATE_IS_ROOT) 
       GetDebugPref(GetPresContext());
 #endif
 
--- a/layout/xul/base/src/nsDeckFrame.h
+++ b/layout/xul/base/src/nsDeckFrame.h
@@ -70,16 +70,20 @@ public:
                                          const nsDisplayListSet& aLists);
                                          
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
 
   virtual nsIAtom* GetType() const;
 
+#ifndef MOZ_GFX_OPTIMIZE_MOBILE
+  virtual PRBool ChildrenMustHaveWidgets() const { return PR_TRUE; }
+#endif
+
 #ifdef NS_DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
       return MakeFrameName(NS_LITERAL_STRING("Deck"), aResult);
   }
 #endif
 
   nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
--- a/layout/xul/base/src/nsLeafBoxFrame.cpp
+++ b/layout/xul/base/src/nsLeafBoxFrame.cpp
@@ -93,16 +93,28 @@ NS_IMETHODIMP
 nsLeafBoxFrame::Init(
               nsIContent*      aContent,
               nsIFrame*        aParent,
               nsIFrame*        aPrevInFlow)
 {
   nsresult  rv = nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
   NS_ENSURE_SUCCESS(rv, rv);
 
+   // see if we need a widget
+  if (aParent && aParent->IsBoxFrame()) {
+    if (aParent->ChildrenMustHaveWidgets()) {
+        rv = nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE); 
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        nsIView* view = GetView();
+        if (!view->HasWidget())
+           view->CreateWidget(kWidgetCID);   
+    }
+  }
+  
   mMouseThrough = unset;
 
   UpdateMouseThrough();
 
   return rv;
 }
 
 NS_IMETHODIMP
--- a/view/public/nsIViewManager.h
+++ b/view/public/nsIViewManager.h
@@ -251,22 +251,17 @@ public:
    * @param RepaintExposedAreaOnly
    *     if PR_TRUE Repaint only the expanded or contracted region,
    *     if PR_FALSE Repaint the union of the old and new rectangles.
    */
   NS_IMETHOD  ResizeView(nsIView *aView, const nsRect &aRect,
                          PRBool aRepaintExposedAreaOnly = PR_FALSE) = 0;
 
   /**
-   * Set the visibility of a view. Hidden views have the effect of hiding
-   * their descendants as well. This does not affect painting, so layout
-   * is responsible for ensuring that content in hidden views is not
-   * painted nor handling events. It does affect the visibility of widgets;
-   * if a view is hidden, descendant views with widgets have their widgets
-   * hidden.
+   * Set the visibility of a view.
    * The view manager generates the appropriate dirty regions.
    * @param aView view to change visibility state of
    * @param visible new visibility state
    */
   NS_IMETHOD  SetViewVisibility(nsIView *aView, nsViewVisibility aVisible) = 0;
 
   /**
    * Set the z-index of a view. Positive z-indices mean that a view
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -47,16 +47,17 @@
 #include "nsIInterfaceRequestor.h"
 
 //mmptemp
 
 static nsEventStatus HandleEvent(nsGUIEvent *aEvent);
 
 
 //#define SHOW_VIEW_BORDERS
+//#define HIDE_ALL_WIDGETS
 
 // {34297A07-A8FD-d811-87C6-000244212BCB}
 #define VIEW_WRAPPER_IID \
 { 0x34297a07, 0xa8fd, 0xd811, { 0x87, 0xc6, 0x0, 0x2, 0x44, 0x21, 0x2b, 0xcb } }
 
 
 /**
  * nsISupports-derived helper class that allows to store and get a view
@@ -332,42 +333,33 @@ void nsView::ResetWidgetBounds(PRBool aR
   } else if (aRecurse) {
     // reposition any widgets under this view
     for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
       v->ResetWidgetBounds(PR_TRUE, aMoveOnly, aInvalidateChangedSize);
     }
   }
 }
 
-PRBool nsView::IsEffectivelyVisible()
-{
-  for (nsView* v = this; v; v = v->mParent) {
-    if (v->GetVisibility() == nsViewVisibility_kHide)
-      return PR_FALSE;
-  }
-  return PR_TRUE;
-}
-
 nsIntRect nsView::CalcWidgetBounds(nsWindowType aType)
 {
   nsCOMPtr<nsIDeviceContext> dx;
   mViewManager->GetDeviceContext(*getter_AddRefs(dx));
   NS_ASSERTION(dx, "View manager can't be created without a device context");
   PRInt32 p2a = dx->AppUnitsPerDevPixel();
 
   nsRect viewBounds(mDimBounds);
 
   if (GetParent()) {
     // put offset into screen coordinates
     nsPoint offset;
     nsIWidget* parentWidget = GetParent()->GetNearestWidget(&offset);
     viewBounds += offset;
 
     if (parentWidget && aType == eWindowType_popup &&
-        IsEffectivelyVisible()) {
+        mVis == nsViewVisibility_kShow) {
       nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset();
       viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
                             NSIntPixelsToAppUnits(screenPoint.y, p2a));
     }
   }
 
   nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
 
@@ -436,48 +428,39 @@ void nsView::SetDimensions(const nsRect&
 
   mDimBounds = dims;
 
   if (aResizeWidget) {
     ResetWidgetBounds(PR_FALSE, PR_FALSE, aPaint);
   }
 }
 
-void nsView::NotifyEffectiveVisibilityChanged(PRBool aEffectivelyVisible)
+NS_IMETHODIMP nsView::SetVisibility(nsViewVisibility aVisibility)
 {
-  if (!aEffectivelyVisible)
+
+  mVis = aVisibility;
+
+  if (aVisibility == nsViewVisibility_kHide)
   {
     DropMouseGrabbing();
   }
 
   if (nsnull != mWindow)
   {
-    if (aEffectivelyVisible)
+#ifndef HIDE_ALL_WIDGETS
+    if (mVis == nsViewVisibility_kShow)
     {
       DoResetWidgetBounds(PR_FALSE, PR_TRUE);
       mWindow->Show(PR_TRUE);
     }
     else
+#endif
       mWindow->Show(PR_FALSE);
   }
 
-  for (nsView* child = mFirstChild; child; child = child->mNextSibling) {
-    if (child->mVis == nsViewVisibility_kHide) {
-      // It was effectively hidden and still is
-      continue;
-    }
-    // Our child is visible if we are
-    child->NotifyEffectiveVisibilityChanged(aEffectivelyVisible);
-  }
-}
-
-NS_IMETHODIMP nsView::SetVisibility(nsViewVisibility aVisibility)
-{
-  mVis = aVisibility;
-  NotifyEffectiveVisibilityChanged(IsEffectivelyVisible());
   return NS_OK;
 }
 
 NS_IMETHODIMP nsView::SetFloating(PRBool aFloatingView)
 {
 	if (aFloatingView)
 		mVFlags |= NS_VIEW_FLAG_FLOATING;
 	else
--- a/view/src/nsView.h
+++ b/view/src/nsView.h
@@ -161,18 +161,16 @@ public:
   // Don't use this method when you want to adjust an nsPoint.
   // Just write "pt -= view->GetPosition();"
   // When everything's converted to nsPoint, this can go away.
   void ConvertFromParentCoords(nscoord* aX, nscoord* aY) const { *aX -= mPosX; *aY -= mPosY; }
   void ResetWidgetBounds(PRBool aRecurse, PRBool aMoveOnly, PRBool aInvalidateChangedSize);
   void SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY);
   nsresult LoadWidget(const nsCID &aClassIID);
 
-  void NotifyEffectiveVisibilityChanged(PRBool aEffectivelyVisible);
-
   // Update the cached RootViewManager for all view manager descendents,
   // If the hierarchy is being removed, aViewManagerParent points to the view
   // manager for the hierarchy's old parent, and will have its mouse grab
   // released if it points to any view in this view hierarchy.
   void InvalidateHierarchy(nsViewManager *aViewManagerParent);
 
   virtual ~nsView();
 
@@ -190,18 +188,16 @@ public:
       // its parent's.
       return mParent->ViewToWidgetOffset();
     }
     return mViewToWidgetOffset;
   }
 
   nsIntRect CalcWidgetBounds(nsWindowType aType);
 
-  PRBool IsEffectivelyVisible();
-
 protected:
   // Do the actual work of ResetWidgetBounds, unconditionally.  Don't
   // call this method if we have no widget.
   void DoResetWidgetBounds(PRBool aMoveOnly, PRBool aInvalidateChangedSize);
 
   nsRegion*    mDirtyRegion;
   nsPoint      mViewToWidgetOffset;
 };
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -105,18 +105,24 @@ public:
     return NS_OK;
   }
 };
 
 //-------------- End Invalidate Event Definition ---------------------------
 
 static PRBool IsViewVisible(nsView *aView)
 {
-  if (!aView->IsEffectivelyVisible())
-    return PR_FALSE;
+  for (nsIView *view = aView; view; view = view->GetParent()) {
+    // We don't check widget visibility here because in the future (with
+    // the better approach to this that's in attachment 160801 on bug
+    // 227361), callers of the equivalent to this function should be able
+    // to rely on being notified when the result of this function changes.
+    if (view->GetVisibility() == nsViewVisibility_kHide)
+      return PR_FALSE;
+  }
 
   // Find out if the root view is visible by asking the view observer
   // (this won't be needed anymore if we link view trees across chrome /
   // content boundaries in DocumentViewerImpl::MakeWindow).
   nsIViewObserver* vo = aView->GetViewManager()->GetViewObserver();
   return vo && vo->IsVisible();
 }
 
@@ -1220,17 +1226,18 @@ nsEventStatus nsViewManager::HandleEvent
 NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult)
 {
   if (!IsRootVM()) {
     return RootViewManager()->GrabMouseEvents(aView, aResult);
   }
 
   // Along with nsView::SetVisibility, we enforce that the mouse grabber
   // can never be a hidden view.
-  if (aView && static_cast<nsView*>(aView)->IsEffectivelyVisible()) {
+  if (aView && static_cast<nsView*>(aView)->GetVisibility()
+               == nsViewVisibility_kHide) {
     aView = nsnull;
   }
 
 #ifdef DEBUG_mjudge
   if (aView)
     {
       printf("capturing mouse events for view %x\n",aView);
     }
@@ -1575,16 +1582,26 @@ NS_IMETHODIMP nsViewManager::SetViewVisi
             UpdateView(parentView, view->GetBounds(), NS_VMREFRESH_NO_SYNC);
           }
         }
         else {
           UpdateView(view, NS_VMREFRESH_NO_SYNC);
         }
       }
     }
+
+    // Any child views not associated with frames might not get their visibility
+    // updated, so propagate our visibility to them. This is important because
+    // hidden views should have all hidden children.
+    for (nsView* childView = view->GetFirstChild(); childView;
+         childView = childView->GetNextSibling()) {
+      if (!childView->GetClientData()) {
+        childView->SetVisibility(aVisible);
+      }
+    }
   }
   return NS_OK;
 }
 
 void nsViewManager::UpdateWidgetsForView(nsView* aView)
 {
   NS_PRECONDITION(aView, "Must have view!");
 
@@ -1945,17 +1962,17 @@ NS_IMETHODIMP nsViewManager::GetRectVisi
   // in order to be counted as visible
 
   *aRectVisibility = nsRectVisibility_kZeroAreaRect;
   if (aRect.width == 0 || aRect.height == 0) {
     return NS_OK;
   }
 
   // is this view even visible?
-  if (!view->IsEffectivelyVisible()) {
+  if (view->GetVisibility() == nsViewVisibility_kHide) {
     return NS_OK; 
   }
 
   // nsViewManager::InsertChild ensures that descendants of floating views
   // are also marked floating.
   if (view->GetFloating()) {
     *aRectVisibility = nsRectVisibility_kVisible;
     return NS_OK;