Bug 800041 - Make nsDisplayWrapList set its own reference frame correctly, and sanity check during ComputeVisibilityForSublist. r=roc

This commit is contained in:
Matt Woodrow 2012-10-25 18:32:25 +13:00
parent 4bc9400593
commit 68ac6cb0e7
2 changed files with 77 additions and 29 deletions

View File

@ -852,7 +852,7 @@ nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
SAMPLE_LABEL("nsDisplayList", "ComputeVisibilityForRoot");
nsRegion r;
r.And(*aVisibleRegion, GetBounds(aBuilder));
return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds(), r.GetBounds());
return ComputeVisibilityForSublist(aBuilder, nullptr, aVisibleRegion, r.GetBounds(), r.GetBounds());
}
static nsRegion
@ -897,6 +897,7 @@ GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
bool
nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aForItem,
nsRegion* aVisibleRegion,
const nsRect& aListVisibleBounds,
const nsRect& aAllowVisibleRegionExpansion) {
@ -919,6 +920,13 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
nsDisplayItem* item = elements[i];
nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1];
NS_ASSERTION(!aForItem ||
item->GetType() != nsDisplayItem::TYPE_TRANSFORM ||
item->GetUnderlyingFrame() != aForItem->GetUnderlyingFrame() ||
aForItem->ReferenceFrame() != aForItem->GetUnderlyingFrame(),
"If we have an nsDisplayTransform child (for the same frame),"
"then we shouldn't be our own reference frame!");
nsDisplayList* list = item->GetList();
if (aBuilder->AllowMergingAndFlattening()) {
if (belowItem && item->TryMerge(aBuilder, belowItem)) {
@ -2374,11 +2382,55 @@ nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
return true;
}
nsIFrame *GetTransformRootFrame(nsIFrame* aFrame)
{
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
while (parent && parent->Preserves3DChildren()) {
parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
}
return parent;
}
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList)
: nsDisplayItem(aBuilder, aFrame) {
mList.AppendToTop(aList);
UpdateBounds(aBuilder);
if (!aFrame || !aFrame->IsTransformed()) {
return;
}
// If the frame is a preserve-3d parent, then we will create transforms
// inside this list afterwards (see WrapPreserve3DList in nsFrame.cpp).
// In this case we will always be outside of the transform, so share
// our parents reference frame.
if (aFrame->Preserves3DChildren()) {
mReferenceFrame =
aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
return;
}
// If we're a transformed frame, then we need to find out if we're inside
// the nsDisplayTransform or outside of it. Frames inside the transform
// need mReferenceFrame == mFrame, outside needs the next ancestor
// reference frame.
// If we're inside the transform, then the nsDisplayItem constructor
// will have done the right thing.
// If we're outside the transform, then we should have only one child
// (since nsDisplayTransform wraps all actual content), and that child
// will have the correct reference frame set (since nsDisplayTransform
// handles this explictly).
//
// Preserve-3d can cause us to have multiple nsDisplayTransform
// children.
nsDisplayItem *i = mList.GetBottom();
if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) &&
i->GetUnderlyingFrame() == mFrame) {
mReferenceFrame = i->ReferenceFrame();
mToReferenceFrame = i->ToReferenceFrame();
}
}
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
@ -2386,6 +2438,23 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
: nsDisplayItem(aBuilder, aFrame) {
mList.AppendToTop(aItem);
UpdateBounds(aBuilder);
if (!aFrame || !aFrame->IsTransformed()) {
return;
}
if (aFrame->Preserves3DChildren()) {
mReferenceFrame =
aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
return;
}
// See the previous nsDisplayWrapList constructor
if (aItem->GetUnderlyingFrame() == aFrame) {
mReferenceFrame = aItem->ReferenceFrame();
mToReferenceFrame = aItem->ToReferenceFrame();
}
}
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
@ -2417,7 +2486,7 @@ bool
nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion) {
return mList.ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
return mList.ComputeVisibilityForSublist(aBuilder, this, aVisibleRegion,
mVisibleRect,
aAllowVisibleRegionExpansion);
}
@ -2780,11 +2849,6 @@ nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
"Need a child frame with content");
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aForFrame);
NS_ASSERTION(parent, "Must have a parent!");
mReferenceFrame =
aBuilder->FindReferenceFrameFor(parent);
mToReferenceFrame = aForFrame->GetOffsetToCrossDoc(mReferenceFrame);
}
nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
@ -2802,11 +2866,6 @@ nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
"Need a child frame with content");
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aForFrame);
NS_ASSERTION(parent, "Must have a parent!");
mReferenceFrame =
aBuilder->FindReferenceFrameFor(parent);
mToReferenceFrame = aForFrame->GetOffsetToCrossDoc(mReferenceFrame);
}
nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
@ -2823,11 +2882,6 @@ nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
"Need a child frame with content");
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aForFrame);
NS_ASSERTION(parent, "Must have a parent!");
mReferenceFrame =
aBuilder->FindReferenceFrameFor(parent);
mToReferenceFrame = aForFrame->GetOffsetToCrossDoc(mReferenceFrame);
}
#ifdef NS_BUILD_REFCNT_LOGGING
@ -2883,7 +2937,7 @@ nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
bool visible = mList.ComputeVisibilityForSublist(
aBuilder, &childVisibleRegion, boundedRect, allowExpansion);
aBuilder, this, &childVisibleRegion, boundedRect, allowExpansion);
mVisibleRect = boundedRect;
return visible;
@ -3232,7 +3286,7 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
nsRect allowExpansion =
aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD);
bool retval =
mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
mList.ComputeVisibilityForSublist(aBuilder, this, &visibleRegion,
transformedVisibleRect,
allowExpansion);
@ -3320,15 +3374,6 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
#endif
nsIFrame *GetTransformRootFrame(nsIFrame* aFrame)
{
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
while (parent && parent->Preserves3DChildren()) {
parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
}
return parent;
}
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
nsDisplayList *aList, ComputeTransformFunction aTransformGetter,
uint32_t aIndex)
@ -4240,7 +4285,7 @@ bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,
// not allow them to subtract area from aVisibleRegion.
nsRegion childrenVisible(dirtyRect);
nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect());
mList.ComputeVisibilityForSublist(aBuilder, this, &childrenVisible, r, nsRect());
return true;
}

View File

@ -692,6 +692,8 @@ public:
if (aFrame) {
mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame);
mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame);
} else {
mReferenceFrame = nullptr;
}
}
nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
@ -1297,6 +1299,7 @@ public:
* @return true if any item in the list is visible.
*/
bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aForItem,
nsRegion* aVisibleRegion,
const nsRect& aListVisibleBounds,
const nsRect& aAllowVisibleRegionExpansion);