Clip now applies to child views. b=11660 r=buster@netscape.com

Prevent the invalidation of hidden views (1/2 patch from <Tomi.Leppikangas@oulu.fi> b=34466 r=buster@netscape.com
Prevent ViewManager1 from getting into endless loops (patch from <jst@citec.fi> b=25336 r=buster@netscape.com
tested=WINNT, Linux, Mac
This commit is contained in:
kmcclusk%netscape.com 2000-04-13 21:56:27 +00:00
parent 0254b96365
commit 1945225950
10 changed files with 192 additions and 64 deletions

View File

@ -551,11 +551,16 @@ nsContainerFrame::SyncFrameViewAfterReflow(nsIPresContext* aPresContext,
if (0 == (NS_STYLE_CLIP_LEFT_AUTO & display->mClipFlags)) {
left += display->mClip.left;
}
aView->SetClip(left, top, right, bottom);
// Set clipping of child views.
aView->SetChildClip(left, top, right, bottom);
PRUint32 vflags;
aView->GetViewFlags(&vflags);
aView->SetViewFlags(vflags | NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN);
} else {
// Make sure no clip is set
aView->SetClip(0, 0, 0, 0);
// Remove clipping of child views.
PRUint32 vflags;
aView->GetViewFlags(&vflags);
aView->SetViewFlags(vflags & ~NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN);
}
}

View File

@ -551,11 +551,16 @@ nsContainerFrame::SyncFrameViewAfterReflow(nsIPresContext* aPresContext,
if (0 == (NS_STYLE_CLIP_LEFT_AUTO & display->mClipFlags)) {
left += display->mClip.left;
}
aView->SetClip(left, top, right, bottom);
// Set clipping of child views.
aView->SetChildClip(left, top, right, bottom);
PRUint32 vflags;
aView->GetViewFlags(&vflags);
aView->SetViewFlags(vflags | NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN);
} else {
// Make sure no clip is set
aView->SetClip(0, 0, 0, 0);
// Remove clipping of child views.
PRUint32 vflags;
aView->GetViewFlags(&vflags);
aView->SetViewFlags(vflags & ~NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN);
}
}

View File

@ -201,14 +201,16 @@ public:
NS_IMETHOD GetBounds(nsRect &aBounds) const = 0;
/**
* Called to indicate that the clip of the view has been changed.
* Called to set the clip of the children of this view.
* The clip is relative to the origin of the view.
* All of the children of this view will be clipped using
* the specified rectangle
* @param aLeft new left position
* @param aTop new top position
* @param aRight new right position
* @param aBottom new bottom position
*/
NS_IMETHOD SetClip(nscoord aLeft, nscoord aTop, nscoord aRight, nscoord aBottom) = 0;
NS_IMETHOD SetChildClip(nscoord aLeft, nscoord aTop, nscoord aRight, nscoord aBottom) = 0;
/**
* Called to get the dimensions and position of the clip for the view.
@ -216,10 +218,8 @@ public:
* @param aTop top position
* @param aRight right position
* @param aBottom bottom position
* @result PR_TRUE of there actually is a clip for the view, else PR_FALSE
*/
NS_IMETHOD GetClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom,
PRBool &aResult) const = 0;
NS_IMETHOD GetChildClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom) const = 0;
/**
* Called to indicate that the visibility of a view has been
@ -507,6 +507,15 @@ public:
*/
NS_IMETHOD SynchWidgetSizePosition() = 0;
/**
* Return a rectangle containing the view's bounds adjusted for it's ancestors clipping
* @param aClippedRect views bounds adjusted for ancestors clipping. If aEmpty is TRUE it
* aClippedRect is set to an empty rect.
* @param aIsClipped returns with PR_TRUE if view's rectangle is clipped by an ancestor
* @param aEmpty returns with PR_TRUE if view's rectangle is 'clipped out'
*/
NS_IMETHOD GetClippedRect(nsRect& aClippedRect, PRBool& aIsClipped, PRBool& aEmpty) const = 0;
private:
NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
@ -565,9 +574,14 @@ private:
#define NS_VIEW_PUBLIC_FLAG_AUTO_ZINDEX 0x0020
// indicatest hat the view is a floating view.
#define NS_VIEW_PUBLIC_FLAG_FLOATING 0x0040
// set if our widget resized.
#define NS_VIEW_PUBLIC_FLAG_WIDGET_RESIZED 0x0080
// set if our widget moved.
#define NS_VIEW_PUBLIC_FLAG_WIDGET_MOVED 0x0100
// indicates that the view should clip its child views using ClipRect specified
// by SetClip
#define NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN 0x0200
#endif

View File

@ -251,12 +251,12 @@ public:
NS_IMETHOD ResizeView(nsIView *aView, nscoord aWidth, nscoord aHeight) = 0;
/**
* Set the clip of a view.
* Set the clipping of a view's children
* The view manager generates the appopriate dirty regions.
* @param aView view to to clip rect on
* @param rect new clipping rect for view
* @param aView view set clip children rect on
* @param rect new clipping rect for view's children
*/
NS_IMETHOD SetViewClip(nsIView *aView, nsRect *aRect) = 0;
NS_IMETHOD SetViewChildClip(nsIView *aView, nsRect *aRect) = 0;
/**
* Set the visibility of a view.

View File

@ -770,7 +770,7 @@ NS_IMETHODIMP nsView :: HandleEvent(nsGUIEvent *event, PRUint32 aEventFlags,
pKid->GetBounds(trect);
if (trect.Contains(x, y))
if (PointIsInside(*pKid, x, y))
{
//the x, y position of the event in question
//is inside this child view, so give it the
@ -1046,29 +1046,23 @@ NS_IMETHODIMP nsView :: GetBounds(nsRect &aBounds) const
return NS_OK;
}
NS_IMETHODIMP nsView :: SetClip(nscoord aLeft, nscoord aTop, nscoord aRight, nscoord aBottom)
NS_IMETHODIMP nsView :: SetChildClip(nscoord aLeft, nscoord aTop, nscoord aRight, nscoord aBottom)
{
NS_PRECONDITION(aLeft <= aRight && aTop <= aBottom, "bad clip values");
mClip.mLeft = aLeft;
mClip.mTop = aTop;
mClip.mRight = aRight;
mClip.mBottom = aBottom;
return NS_OK;
}
NS_IMETHODIMP nsView :: GetClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom,
PRBool &aResult) const
NS_IMETHODIMP nsView :: GetChildClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom) const
{
if ((mClip.mLeft == mClip.mRight) || (mClip.mTop == mClip.mBottom)) {
aResult = PR_FALSE;
} else {
*aLeft = mClip.mLeft;
*aTop = mClip.mTop;
*aRight = mClip.mRight;
*aBottom = mClip.mBottom;
aResult = PR_TRUE;
}
*aLeft = mClip.mLeft;
*aTop = mClip.mTop;
*aRight = mClip.mRight;
*aBottom = mClip.mBottom;
return NS_OK;
}
@ -1612,3 +1606,77 @@ nsIView *rootView;
return PR_FALSE;
}
PRBool nsView::PointIsInside(nsIView& aView, nscoord x, nscoord y) const
{
nsRect clippedRect;
PRBool empty;
PRBool clipped;
aView.GetClippedRect(clippedRect, clipped, empty);
if (PR_TRUE == empty) {
// Rect is completely clipped out so point can not
// be inside it.
return PR_FALSE;
}
// Check to see if the point is within the clipped rect.
if (clippedRect.Contains(x, y)) {
return PR_TRUE;
} else {
return PR_FALSE;
}
}
NS_IMETHODIMP nsView::GetClippedRect(nsRect& aClippedRect, PRBool& aIsClipped, PRBool& aEmpty) const
{
// Keep track of the view's offset
// from its ancestor.
nscoord ancestorX = 0;
nscoord ancestorY = 0;
aEmpty = PR_FALSE;
aIsClipped = PR_FALSE;
GetBounds(aClippedRect);
nsIView* parentView;
GetParent(parentView);
// Walk all of the way up the views to see if any
// ancestor sets the NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN
while (parentView) {
PRUint32 flags;
parentView->GetViewFlags(&flags);
if (flags & NS_VIEW_PUBLIC_FLAG_CLIPCHILDREN) {
aIsClipped = PR_TRUE;
// Adjust for clip specified by ancestor
nscoord clipLeft;
nscoord clipTop;
nscoord clipRight;
nscoord clipBottom;
parentView->GetChildClip(&clipLeft, &clipTop, &clipRight, &clipBottom);
nsRect clipRect;
//Offset the cliprect by the amount the child offsets from the parent
clipRect.x = clipLeft + ancestorX;
clipRect.y = clipTop + ancestorY;
clipRect.width = clipRight - clipLeft;
clipRect.height = clipBottom - clipTop;
PRBool overlap = aClippedRect.IntersectRect(clipRect, aClippedRect);
if (!overlap) {
aEmpty = PR_TRUE; // Does not intersect so the rect is empty.
return NS_OK;
}
}
nsRect bounds;
parentView->GetBounds(bounds);
ancestorX -= bounds.x;
ancestorY -= bounds.y;
parentView->GetParent(parentView);
}
return NS_OK;
}

View File

@ -66,8 +66,8 @@ public:
NS_IMETHOD SetBounds(const nsRect &aBounds, PRBool aPaint = PR_TRUE);
NS_IMETHOD SetBounds(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aPaint = PR_TRUE);
NS_IMETHOD GetBounds(nsRect &aBounds) const;
NS_IMETHOD SetClip(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight);
NS_IMETHOD GetClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom, PRBool &aResult) const;
NS_IMETHOD SetChildClip(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight);
NS_IMETHOD GetChildClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom) const;
NS_IMETHOD SetVisibility(nsViewVisibility visibility);
NS_IMETHOD GetVisibility(nsViewVisibility &aVisibility) const;
NS_IMETHOD SetZIndex(PRInt32 aZIndex);
@ -109,11 +109,13 @@ public:
NS_IMETHOD SetCompositorFlags(PRUint32 aFlags);
NS_IMETHOD GetCompositorFlags(PRUint32 *aFlags);
NS_IMETHOD GetExtents(nsRect *aExtents);
NS_IMETHOD GetClippedRect(nsRect& aClippedRect, PRBool& aIsClipped, PRBool& aEmpty) const;
// XXX Temporary for Bug #19416
NS_IMETHOD IgnoreSetPosition(PRBool aShouldIgnore);
NS_IMETHOD SynchWidgetSizePosition();
NS_IMETHOD SynchWidgetSizePosition();
// Helper function to get the view that's associated with a widget
@ -122,6 +124,9 @@ public:
// Helper function to determine if the view instance is the root view
PRBool IsRoot();
// Helper function to determine if the view point is inside of a view
PRBool PointIsInside(nsIView& aView, nscoord x, nscoord y) const;
protected:
virtual ~nsView();
//

View File

@ -1112,7 +1112,7 @@ void nsViewManager :: RenderViews(nsIView *aRootView, nsIRenderingContext& aRC,
NS_ASSERTION((pushcnt >= 0), "underflow");
while (pushcnt--)
while (pushcnt-- > 0)
{
NS_ASSERTION((pushcnt >= 0), "underflow");
@ -2007,12 +2007,12 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, nscoord width, nscoord h
return NS_OK;
}
NS_IMETHODIMP nsViewManager :: SetViewClip(nsIView *aView, nsRect *aRect)
NS_IMETHODIMP nsViewManager :: SetViewChildClip(nsIView *aView, nsRect *aRect)
{
NS_ASSERTION(!(nsnull == aView), "no view");
NS_ASSERTION(!(nsnull == aRect), "no clip");
aView->SetClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost());
aView->SetChildClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost());
UpdateView(aView, *aRect, NS_VMREFRESH_NO_SYNC);

View File

@ -101,7 +101,7 @@ public:
NS_IMETHOD ResizeView(nsIView *aView, nscoord aWidth, nscoord aHeight);
NS_IMETHOD SetViewClip(nsIView *aView, nsRect *aRect);
NS_IMETHOD SetViewChildClip(nsIView *aView, nsRect *aRect);
NS_IMETHOD SetViewVisibility(nsIView *aView, nsViewVisibility aVisible);

View File

@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s): Patrick C. Beard <beard@netscape.com>
* Kevin McCluskey <kmcclusk@netscape.com>
*/
#include "nsViewManager2.h"
@ -52,6 +53,7 @@ static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
#define POP_CLIP 0x00000004
#define VIEW_TRANSPARENT 0x00000008
#define VIEW_TRANSLUCENT 0x00000010
#define VIEW_CLIPPED 0x00000020
// Uncomment the following to use the nsIBlender. Turned off for now,
// so that we won't crash.
@ -733,7 +735,16 @@ void nsViewManager2::RenderViews(nsIView *aRootView, nsIRenderingContext& aRC, c
if (element->mFlags & VIEW_RENDERED) {
// typical case, just rendering a view.
// RenderView(element->mView, aRC, aRect, element->mBounds, aResult);
RenderDisplayListElement(element, aRC);
if (element->mFlags & VIEW_CLIPPED) {
//Render the view using the clip rect set by it's ancestors
aRC.PushState();
aRC.SetClipRect(element->mBounds, nsClipCombine_kIntersect, clipEmpty);
RenderDisplayListElement(element, aRC);
aRC.PopState(clipEmpty);
} else {
RenderDisplayListElement(element, aRC);
}
} else {
// special case, pushing or popping clipping.
if (element->mFlags & PUSH_CLIP) {
@ -1080,28 +1091,18 @@ NS_IMETHODIMP nsViewManager2::UpdateView(nsIView *aView, const nsRect &aRect, PR
// without invalidating. This is a performance
// enhancement since invalidating a native widget
// can be expensive.
// This also checks for silly request like aRect.width = 0 or aRect.height = 0
if (! IsRectVisible(aView, aRect)) {
return NS_OK;
}
if (!mRefreshEnabled) {
// accumulate this rectangle in the view's dirty region, so we can process it later.
if (aRect.width != 0 && aRect.height != 0) {
AddRectToDirtyRegion(aView, aRect);
++mUpdateCnt;
}
AddRectToDirtyRegion(aView, aRect);
++mUpdateCnt;
return NS_OK;
}
// Ignore any silly requests...
if ((aRect.width == 0) || (aRect.height == 0))
return NS_OK;
// is this view even visible?
nsViewVisibility visibility;
aView->GetVisibility(visibility);
if (visibility == nsViewVisibility_kHide)
return NS_OK;
// Find the nearest view (including this view) that has a widget
nsIView *widgetView = GetWidgetView(aView);
@ -1598,12 +1599,12 @@ NS_IMETHODIMP nsViewManager2::ResizeView(nsIView *aView, nscoord width, nscoord
return NS_OK;
}
NS_IMETHODIMP nsViewManager2::SetViewClip(nsIView *aView, nsRect *aRect)
NS_IMETHODIMP nsViewManager2::SetViewChildClip(nsIView *aView, nsRect *aRect)
{
NS_ASSERTION(!(nsnull == aView), "no view");
NS_ASSERTION(!(nsnull == aRect), "no clip");
aView->SetClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost());
aView->SetChildClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost());
UpdateView(aView, *aRect, NS_VMREFRESH_NO_SYNC);
@ -2190,7 +2191,8 @@ PRBool nsViewManager2::CreateDisplayList(nsIView *aView, PRInt32 *aIndex,
aTopView = aView;
nsRect bounds;
aView->GetBounds(bounds);
aView->GetBounds(bounds);
if (aView == aTopView) {
bounds.x = 0;
@ -2218,7 +2220,7 @@ PRBool nsViewManager2::CreateDisplayList(nsIView *aView, PRInt32 *aIndex,
bounds.x -= aOriginX;
bounds.y -= aOriginY;
retval = AddToDisplayList(aIndex, aView, bounds, bounds, POP_CLIP);
retval = AddToDisplayList(aIndex, aView, bounds, bounds, POP_CLIP, aX, aY);
if (retval)
return retval;
@ -2249,8 +2251,9 @@ PRBool nsViewManager2::CreateDisplayList(nsIView *aView, PRInt32 *aIndex,
// if (clipper)
if (isClipView && (!hasWidget || (hasWidget && isParentView))) {
if (childCount > 0)
retval = AddToDisplayList(aIndex, aView, bounds, bounds, PUSH_CLIP);
if (childCount > 0) {
retval = AddToDisplayList(aIndex, aView, bounds, bounds, PUSH_CLIP, aX, aY);
}
} else if (!retval) {
nsViewVisibility visibility;
float opacity;
@ -2275,7 +2278,7 @@ PRBool nsViewManager2::CreateDisplayList(nsIView *aView, PRInt32 *aIndex,
if (opacity < 1.0f)
flags |= VIEW_TRANSLUCENT;
#endif
retval = AddToDisplayList(aIndex, aView, bounds, irect, flags);
retval = AddToDisplayList(aIndex, aView, bounds, irect, flags, aX, aY);
if (retval || !transparent && (opacity == 1.0f) && (irect == *aDamageRect))
retval = PR_TRUE;
@ -2296,8 +2299,12 @@ PRBool nsViewManager2::CreateDisplayList(nsIView *aView, PRInt32 *aIndex,
return retval;
}
PRBool nsViewManager2::AddToDisplayList(PRInt32 *aIndex, nsIView *aView, nsRect &aClipRect, nsRect& aDirtyRect, PRUint32 aFlags)
PRBool nsViewManager2::AddToDisplayList(PRInt32 *aIndex, nsIView *aView, nsRect &aClipRect, nsRect& aDirtyRect, PRUint32 aFlags,nscoord aAbsX, nscoord aAbsY)
{
PRBool empty;
PRBool clipped;
nsRect clipRect;
PRInt32 index = (*aIndex)++;
DisplayListElement2* element = (DisplayListElement2*) mDisplayList->ElementAt(index);
if (element == nsnull) {
@ -2309,10 +2316,23 @@ PRBool nsViewManager2::AddToDisplayList(PRInt32 *aIndex, nsIView *aView, nsRect
mDisplayList->ReplaceElementAt(element, index);
}
// Calculate absolute clipped position of view
aView->GetClippedRect(clipRect, clipped, empty);
clipRect.x += aAbsX;
clipRect.y += aAbsY;
element->mView = aView;
element->mBounds = aClipRect;
element->mDirty = aDirtyRect;
element->mFlags = aFlags;
if (clipped) {
// Use bounds calculated by above and indicate
// it should be clipped
element->mBounds = clipRect;
element->mFlags = aFlags | VIEW_CLIPPED;
} else {
// Use the bounds passed in
element->mBounds = aClipRect;
element->mFlags = aFlags;
}
// count number of opaque views.
if (aFlags == VIEW_RENDERED)
@ -2574,6 +2594,17 @@ nsresult nsViewManager2::GetAbsoluteRect(nsIView *aView, const nsRect &aRect,
PRBool nsViewManager2::IsRectVisible(nsIView *aView, const nsRect &aRect)
{
if (aRect.width == 0 || aRect.height == 0) {
return PR_FALSE;
}
// is this view even visible?
nsViewVisibility visibility;
aView->GetVisibility(visibility);
if (visibility == nsViewVisibility_kHide) {
return PR_FALSE;
}
// Calculate the absolute coordinates for the visible rectangle
nsRect visibleRect;
if (GetVisibleRect(visibleRect) == NS_ERROR_FAILURE) {

View File

@ -103,7 +103,7 @@ public:
NS_IMETHOD ResizeView(nsIView *aView, nscoord aWidth, nscoord aHeight);
NS_IMETHOD SetViewClip(nsIView *aView, nsRect *aRect);
NS_IMETHOD SetViewChildClip(nsIView *aView, nsRect *aRect);
NS_IMETHOD SetViewVisibility(nsIView *aView, nsViewVisibility aVisible);
@ -185,7 +185,7 @@ private:
PRBool CreateDisplayList(nsIView *aView, PRInt32 *aIndex, nscoord aOriginX, nscoord aOriginY,
nsIView *aRealView, const nsRect *aDamageRect = nsnull,
nsIView *aTopView = nsnull, nscoord aX = 0, nscoord aY = 0);
PRBool AddToDisplayList(PRInt32 *aIndex, nsIView *aView, nsRect &aClipRect, nsRect& aDirtyRect, PRUint32 aFlags);
PRBool AddToDisplayList(PRInt32 *aIndex, nsIView *aView, nsRect &aClipRect, nsRect& aDirtyRect, PRUint32 aFlags, nscoord aAbsX, nscoord aAbsY);
nsresult OptimizeDisplayList(const nsRect& aDamageRect);
void ShowDisplayList(PRInt32 flatlen);
void ComputeViewOffset(nsIView *aView, nsPoint *aOrigin, PRInt32 aFlag);