mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Bug 171334. r=kmcclusk,sr=kin,a=asa. Fix views crasher by eliminating content-parenting nesting assumptions.
This commit is contained in:
parent
ff5152a1e2
commit
ca03aa9d86
@ -90,10 +90,13 @@ nsView::nsView()
|
||||
MOZ_COUNT_CTOR(nsView);
|
||||
|
||||
mVis = nsViewVisibility_kShow;
|
||||
mVFlags = 0;
|
||||
// Views should be transparent by default. Not being transparent is
|
||||
// a promise that the view will paint all its pixels opaquely. Views
|
||||
// should make this promise explicitly by calling
|
||||
// SetViewContentTransparency.
|
||||
mVFlags = NS_VIEW_FLAG_TRANSPARENT;
|
||||
mOpacity = 1.0f;
|
||||
mViewManager = nsnull;
|
||||
mCompositorFlags = 0;
|
||||
mChildRemoved = PR_FALSE;
|
||||
}
|
||||
|
||||
@ -944,19 +947,6 @@ nsresult nsView::GetDirtyRegion(nsIRegion*& aRegion)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsView::SetCompositorFlags(PRUint32 aFlags)
|
||||
{
|
||||
mCompositorFlags = aFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsView::GetCompositorFlags(PRUint32 *aFlags)
|
||||
{
|
||||
NS_ASSERTION((aFlags != nsnull), "no flags");
|
||||
*aFlags = mCompositorFlags;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool nsView::IsRoot()
|
||||
{
|
||||
NS_ASSERTION(mViewManager != nsnull," View manager is null in nsView::IsRoot()");
|
||||
@ -985,7 +975,7 @@ PRBool nsView::PointIsInside(nsView& aView, nscoord x, nscoord y) const
|
||||
|
||||
NS_IMETHODIMP nsView::GetClippedRect(nsRect& aClippedRect, PRBool& aIsClipped, PRBool& aEmpty) const
|
||||
{
|
||||
// Keep track of the view's offset from its ancestor.
|
||||
// Keep track of this view's offset from its ancestor.
|
||||
// This is the origin of this view's parent view in the
|
||||
// coordinate space of 'parentView' below.
|
||||
nscoord ancestorX = 0;
|
||||
@ -1005,21 +995,28 @@ NS_IMETHODIMP nsView::GetClippedRect(nsRect& aClippedRect, PRBool& aIsClipped, P
|
||||
const nsView* zParent = view->GetZParent();
|
||||
const nsView* parentView = view->GetParent();
|
||||
if (zParent) {
|
||||
// This view was reparented. We need to move back down the view tree
|
||||
// to where it should be to collect whatever might be clipping it there.
|
||||
// This view was reparented. We need to continue collecting clip
|
||||
// rects from the zParent.
|
||||
|
||||
// parentView is an ancestor of zParent ... this is guaranteed by the way these
|
||||
// reparented views are set up; a reparented view is always reparented to one of its
|
||||
// own ancestors
|
||||
|
||||
// we need to get ancestorX and ancestorY into the right coordinate system.
|
||||
// They are the offset of this view within parentView
|
||||
// First we need to get ancestorX and ancestorY into the right
|
||||
// coordinate system. They are the offset of this view within
|
||||
// parentView
|
||||
const nsView* zParentChain;
|
||||
for (zParentChain = zParent; zParentChain != parentView;
|
||||
for (zParentChain = zParent; zParentChain != parentView && zParentChain != nsnull;
|
||||
zParentChain = zParentChain->GetParent()) {
|
||||
NS_ASSERTION(zParentChain != nsnull, "Error in view reparenting logic");
|
||||
zParentChain->ConvertFromParentCoords(&ancestorX, &ancestorY);
|
||||
}
|
||||
if (zParentChain == nsnull) {
|
||||
// normally we'll hit parentView somewhere, but sometimes we
|
||||
// don't because of odd containing block hierarchies. In this
|
||||
// case we walked from zParentChain all the way up to the
|
||||
// root, subtracting from ancestorX/Y. So now we walk from
|
||||
// parentView up to the root, adding to ancestorX/Y.
|
||||
while (parentView != nsnull) {
|
||||
parentView->ConvertToParentCoords(&ancestorX, &ancestorY);
|
||||
parentView = parentView->GetParent();
|
||||
}
|
||||
}
|
||||
parentView = zParent;
|
||||
// Now start again at zParent to collect all its clip information
|
||||
}
|
||||
|
@ -66,27 +66,37 @@ public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICLIPVIEW_IID)
|
||||
};
|
||||
|
||||
//Flag to determine whether the view will check if events can be handled
|
||||
//by its children or just handle the events itself
|
||||
#define NS_VIEW_FLAG_DONT_CHECK_CHILDREN 0x0001
|
||||
|
||||
// indicates that the view is or contains a placeholder view
|
||||
#define NS_VIEW_FLAG_CONTAINS_PLACEHOLDER 0x0002
|
||||
|
||||
//the view is transparent
|
||||
#define NS_VIEW_FLAG_TRANSPARENT 0x0004
|
||||
|
||||
//indicates that the view should not be bitblt'd when moved
|
||||
//or scrolled and instead must be repainted
|
||||
#define NS_VIEW_FLAG_DONT_BITBLT 0x0010
|
||||
|
||||
// indicates that the view is using auto z-indexing
|
||||
#define NS_VIEW_FLAG_AUTO_ZINDEX 0x0020
|
||||
|
||||
// indicates that the view is a floating view.
|
||||
#define NS_VIEW_FLAG_FLOATING 0x0040
|
||||
|
||||
// set if our widget resized.
|
||||
#define NS_VIEW_FLAG_WIDGET_RESIZED 0x0080
|
||||
|
||||
// set if our widget moved.
|
||||
#define NS_VIEW_FLAG_WIDGET_MOVED 0x0100
|
||||
#define NS_VIEW_FLAG_CLIPCHILDREN 0x0200
|
||||
|
||||
// if set it indicates that this view should be
|
||||
// displayed above z-index:auto views if this view
|
||||
// is z-index:auto also
|
||||
#define NS_VIEW_FLAG_TOPMOST 0x0400
|
||||
//indicates that the view should not be bitblt'd when moved
|
||||
//or scrolled and instead must be repainted
|
||||
#define NS_VIEW_FLAG_DONT_BITBLT 0x0010
|
||||
//Flag to determine whether the view will check if events can be handled
|
||||
//by its children or just handle the events itself
|
||||
#define NS_VIEW_FLAG_DONT_CHECK_CHILDREN 0x0001
|
||||
|
||||
class nsView : public nsIView
|
||||
{
|
||||
@ -180,6 +190,12 @@ public:
|
||||
void GetDimensions(nsRect &aRect) const { aRect = mDimBounds; aRect.x -= mPosX; aRect.y -= mPosY; }
|
||||
void GetDimensions(nsSize &aSize) const { aSize.width = mDimBounds.width; aSize.height = mDimBounds.height; }
|
||||
|
||||
/**
|
||||
* This checks whether the view is a placeholder for some view that has
|
||||
* been reparented to a different geometric parent.
|
||||
*/
|
||||
virtual PRBool IsZPlaceholderView() { return PR_FALSE; }
|
||||
|
||||
/**
|
||||
* Called to set the clip of the children of this view.
|
||||
* The clip is relative to the origin of the view.
|
||||
@ -251,12 +267,6 @@ public:
|
||||
* @return error status
|
||||
*/
|
||||
NS_IMETHOD SetWidget(nsIWidget *aWidget);
|
||||
/**
|
||||
* Used by the compositor for temporary marking of a view during
|
||||
* compositing. This will eventually replace GetScratchPoint above.
|
||||
*/
|
||||
NS_IMETHOD SetCompositorFlags(PRUint32 aFlags);
|
||||
NS_IMETHOD GetCompositorFlags(PRUint32 *aFlags);
|
||||
/**
|
||||
* 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
|
||||
@ -338,7 +348,6 @@ protected:
|
||||
float mOpacity;
|
||||
PRUint32 mVFlags;
|
||||
nsIRegion* mDirtyRegion;
|
||||
PRUint32 mCompositorFlags;
|
||||
// Bug #19416
|
||||
PRPackedBool mShouldIgnoreSetPosition;
|
||||
PRPackedBool mChildRemoved;
|
||||
|
@ -1962,6 +1962,71 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsViewManager::ReparentViews(DisplayZTreeNode* aNode) {
|
||||
if (aNode == nsnull) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayZTreeNode* child;
|
||||
DisplayZTreeNode** prev = &aNode->mZChild;
|
||||
for (child = aNode->mZChild; nsnull != child; child = *prev) {
|
||||
ReparentViews(child);
|
||||
|
||||
nsZPlaceholderView *zParent = nsnull;
|
||||
if (nsnull != child->mView) {
|
||||
zParent = child->mView->GetZParent();
|
||||
}
|
||||
if (nsnull != zParent) {
|
||||
nsVoidKey key(zParent);
|
||||
DisplayZTreeNode* placeholder = (DisplayZTreeNode *)mMapPlaceholderViewToZTreeNode.Get(&key);
|
||||
|
||||
if (placeholder == child) {
|
||||
// don't do anything if we already reparented this node;
|
||||
// just advance to the next child
|
||||
prev = &child->mZSibling;
|
||||
} else {
|
||||
// unlink the child from the tree
|
||||
*prev = child->mZSibling;
|
||||
child->mZSibling = nsnull;
|
||||
|
||||
if (nsnull != placeholder) {
|
||||
NS_ASSERTION((placeholder->mDisplayElement == nsnull), "placeholder already has elements?");
|
||||
NS_ASSERTION((placeholder->mZChild == nsnull), "placeholder already has Z-children?");
|
||||
placeholder->mDisplayElement = child->mDisplayElement;
|
||||
placeholder->mView = child->mView;
|
||||
placeholder->mZChild = child->mZChild;
|
||||
delete child;
|
||||
} else {
|
||||
// the placeholder was not added to the display list
|
||||
// we don't need the real view then, either
|
||||
DestroyZTreeNode(child);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prev = &child->mZSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool ComputePlaceholderContainment(nsView* aView) {
|
||||
PRBool containsPlaceholder = aView->IsZPlaceholderView();
|
||||
|
||||
nsView* child;
|
||||
for (child = aView->GetFirstChild(); child != nsnull; child = child->GetNextSibling()) {
|
||||
if (ComputePlaceholderContainment(child)) {
|
||||
containsPlaceholder = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (containsPlaceholder) {
|
||||
aView->SetViewFlags(aView->GetViewFlags() | NS_VIEW_FLAG_CONTAINS_PLACEHOLDER);
|
||||
} else {
|
||||
aView->SetViewFlags(aView->GetViewFlags() & ~NS_VIEW_FLAG_CONTAINS_PLACEHOLDER);
|
||||
}
|
||||
|
||||
return containsPlaceholder;
|
||||
}
|
||||
|
||||
/*
|
||||
Fills mDisplayList with DisplayListElement2* pointers. The caller is responsible
|
||||
for freeing these structs. The display list elements are ordered by z-order so
|
||||
@ -2006,6 +2071,9 @@ void nsViewManager::BuildDisplayList(nsView* aView, const nsRect& aRect, PRBool
|
||||
nsPoint displayRootOrigin(0, 0);
|
||||
ComputeViewOffset(displayRoot, &displayRootOrigin);
|
||||
|
||||
// Determine, for each view, whether it is or contains a ZPlaceholderView
|
||||
ComputePlaceholderContainment(displayRoot);
|
||||
|
||||
// Create the Z-ordered view tree
|
||||
PRBool paintFloaters;
|
||||
if (aEventProcessing) {
|
||||
@ -2015,6 +2083,9 @@ void nsViewManager::BuildDisplayList(nsView* aView, const nsRect& aRect, PRBool
|
||||
}
|
||||
CreateDisplayList(displayRoot, PR_FALSE, zTree, PR_FALSE, origin.x, origin.y,
|
||||
aView, &aRect, nsnull, displayRootOrigin.x, displayRootOrigin.y, paintFloaters, aEventProcessing);
|
||||
|
||||
// Reparent any views that need reparenting in the Z-order tree
|
||||
ReparentViews(zTree);
|
||||
mMapPlaceholderViewToZTreeNode.Reset();
|
||||
|
||||
if (nsnull != zTree) {
|
||||
@ -3353,7 +3424,21 @@ PRBool nsViewManager::CreateDisplayList(nsView *aView, PRBool aReparentedViewsPr
|
||||
bounds.x += aOriginX;
|
||||
bounds.y += aOriginY;
|
||||
|
||||
if (!overlap && isClipView) {
|
||||
// if there's no overlap between the dirty area and the bounds of
|
||||
// the view, we should be able to ignore the view and all its
|
||||
// children. Unfortunately there is the possibility of reparenting:
|
||||
// some other view in the tree might want to be reparented to one of
|
||||
// our children, and that view might lie outside our
|
||||
// bounds. Typically we need to go ahead and add this view and its
|
||||
// children to the ZTree in case someone wants to reparent into it.
|
||||
//
|
||||
// We can avoid this in two cases: if we clip our children to our
|
||||
// bounds, then even if a view is reparented under us, none of its
|
||||
// visible area can lie outside our bounds, so it can't intersect
|
||||
// the dirty area. Also, if we don't contain any placeholder views,
|
||||
// then there is no way for anyone to reparent below us.
|
||||
if (!overlap && (isClipView ||
|
||||
(aView->GetViewFlags() & NS_VIEW_FLAG_CONTAINS_PLACEHOLDER) == 0)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
@ -3369,21 +3454,6 @@ PRBool nsViewManager::CreateDisplayList(nsView *aView, PRBool aReparentedViewsPr
|
||||
}
|
||||
}
|
||||
|
||||
if (!aReparentedViewsPresent) {
|
||||
for (nsView* childView = aView->GetFirstChild(); nsnull != childView;
|
||||
childView = childView->GetNextSibling()) {
|
||||
nsZPlaceholderView *zParent = childView->GetZParent();
|
||||
if (nsnull != zParent) {
|
||||
aReparentedViewsPresent = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!overlap && !aReparentedViewsPresent) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 childCount = aView->GetChildCount();
|
||||
nsView *childView = nsnull;
|
||||
|
||||
@ -3458,10 +3528,7 @@ PRBool nsViewManager::CreateDisplayList(nsView *aView, PRBool aReparentedViewsPr
|
||||
bounds.x += aOriginX;
|
||||
bounds.y += aOriginY;
|
||||
} else {
|
||||
PRUint32 compositorFlags = 0;
|
||||
aView->GetCompositorFlags(&compositorFlags);
|
||||
|
||||
if (0 != (compositorFlags & IS_Z_PLACEHOLDER_VIEW)) {
|
||||
if (aView->IsZPlaceholderView()) {
|
||||
EnsureZTreeNodeCreated(aView, aResult);
|
||||
mMapPlaceholderViewToZTreeNode.Put(new nsVoidKey(aView), aResult);
|
||||
}
|
||||
@ -3497,41 +3564,6 @@ PRBool nsViewManager::CreateDisplayList(nsView *aView, PRBool aReparentedViewsPr
|
||||
}
|
||||
}
|
||||
|
||||
// Reparent any views that need reparenting in the Z-order tree
|
||||
if (nsnull != aResult) {
|
||||
DisplayZTreeNode* child;
|
||||
DisplayZTreeNode** prev = &aResult->mZChild;
|
||||
for (child = aResult->mZChild; nsnull != child; child = *prev) {
|
||||
nsZPlaceholderView *zParent = nsnull;
|
||||
if (nsnull != child->mView) {
|
||||
zParent = child->mView->GetZParent();
|
||||
}
|
||||
if (nsnull != zParent) {
|
||||
// unlink the child from the tree
|
||||
*prev = child->mZSibling;
|
||||
child->mZSibling = nsnull;
|
||||
|
||||
nsVoidKey key(zParent);
|
||||
DisplayZTreeNode* placeholder = (DisplayZTreeNode *)mMapPlaceholderViewToZTreeNode.Remove(&key);
|
||||
|
||||
if (nsnull != placeholder) {
|
||||
NS_ASSERTION((placeholder->mDisplayElement == nsnull), "placeholder already has elements?");
|
||||
NS_ASSERTION((placeholder->mZChild == nsnull), "placeholder already has Z-children?");
|
||||
placeholder->mDisplayElement = child->mDisplayElement;
|
||||
placeholder->mView = child->mView;
|
||||
placeholder->mZChild = child->mZChild;
|
||||
delete child;
|
||||
} else {
|
||||
// the placeholder was never added to the display list ...
|
||||
// we don't need to display this then
|
||||
DestroyZTreeNode(child);
|
||||
}
|
||||
} else {
|
||||
prev = &child->mZSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -70,10 +70,6 @@ struct DisplayZTreeNode;
|
||||
#include "nsTimer.h"
|
||||
#endif
|
||||
|
||||
// compositor per-view flags
|
||||
#define IS_PARENT_OF_REFRESHED_VIEW 0x00000001
|
||||
#define IS_Z_PLACEHOLDER_VIEW 0x80000000
|
||||
|
||||
/**
|
||||
FIXED-POSITION FRAMES AND Z-ORDERING
|
||||
|
||||
@ -105,8 +101,7 @@ public:
|
||||
void SetReparentedView(nsView* aView) { mReparentedView = aView; }
|
||||
nsView* GetReparentedView() { return mReparentedView; }
|
||||
|
||||
NS_IMETHOD GetCompositorFlags(PRUint32 *aFlags)
|
||||
{ nsView::GetCompositorFlags(aFlags); *aFlags |= IS_Z_PLACEHOLDER_VIEW; return NS_OK; }
|
||||
virtual PRBool IsZPlaceholderView() { return PR_TRUE; }
|
||||
|
||||
protected:
|
||||
virtual ~nsZPlaceholderView() {
|
||||
@ -271,6 +266,7 @@ private:
|
||||
|
||||
nsresult CreateBlendingBuffers(nsIRenderingContext &aRC);
|
||||
|
||||
void ReparentViews(DisplayZTreeNode* aNode);
|
||||
void BuildDisplayList(nsView* aView, const nsRect& aRect, PRBool aEventProcessing, PRBool aCaptured);
|
||||
void BuildEventTargetList(nsAutoVoidArray &aTargets, nsView* aView, nsGUIEvent* aEvent, PRBool aCaptured);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user