diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 64fd2645749..11a7e5c83d8 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -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; } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 81dc3acec96..b7a84ec607b 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -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);