Bug 506615. XUL decks should not have wididgets. r=dbaron
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -612,21 +612,20 @@ 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 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?
+ // 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.
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,25 +6712,16 @@ 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,20 +102,19 @@ 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 \
- { 0x7b437d20, 0xa34e, 0x11dd, \
- { 0xad, 0x8b, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
+ { 0x7e9018b5, 0x5405, 0x4e2b, \
+ { 0x87, 0x67, 0xe2, 0xb4, 0xb1, 0x3e, 0xc1, 0x69 } }
/**
* 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.
@@ -2281,19 +2280,16 @@ 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,28 +200,16 @@ 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,20 +70,16 @@ 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,28 +93,16 @@ 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,17 +251,22 @@ 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.
+ * 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.
* 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,17 +47,16 @@
#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
@@ -333,33 +332,42 @@ 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 &&
- mVis == nsViewVisibility_kShow) {
+ IsEffectivelyVisible()) {
nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset();
viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
NSIntPixelsToAppUnits(screenPoint.y, p2a));
}
}
nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
@@ -428,39 +436,48 @@ void nsView::SetDimensions(const nsRect&
mDimBounds = dims;
if (aResizeWidget) {
ResetWidgetBounds(PR_FALSE, PR_FALSE, aPaint);
}
}
-NS_IMETHODIMP nsView::SetVisibility(nsViewVisibility aVisibility)
+void nsView::NotifyEffectiveVisibilityChanged(PRBool aEffectivelyVisible)
{
-
- mVis = aVisibility;
-
- if (aVisibility == nsViewVisibility_kHide)
+ if (!aEffectivelyVisible)
{
DropMouseGrabbing();
}
if (nsnull != mWindow)
{
-#ifndef HIDE_ALL_WIDGETS
- if (mVis == nsViewVisibility_kShow)
+ if (aEffectivelyVisible)
{
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,16 +161,18 @@ 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();
@@ -188,16 +190,18 @@ 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,24 +105,18 @@ public:
return NS_OK;
}
};
//-------------- End Invalidate Event Definition ---------------------------
static PRBool IsViewVisible(nsView *aView)
{
- 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;
- }
+ if (!aView->IsEffectivelyVisible())
+ 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();
}
@@ -1226,18 +1220,17 @@ 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)->GetVisibility()
- == nsViewVisibility_kHide) {
+ if (aView && static_cast<nsView*>(aView)->IsEffectivelyVisible()) {
aView = nsnull;
}
#ifdef DEBUG_mjudge
if (aView)
{
printf("capturing mouse events for view %x\n",aView);
}
@@ -1582,26 +1575,16 @@ 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!");
@@ -1962,17 +1945,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->GetVisibility() == nsViewVisibility_kHide) {
+ if (!view->IsEffectivelyVisible()) {
return NS_OK;
}
// nsViewManager::InsertChild ensures that descendants of floating views
// are also marked floating.
if (view->GetFloating()) {
*aRectVisibility = nsRectVisibility_kVisible;
return NS_OK;