diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index ccff799acac..55ec4803360 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2451,13 +2451,6 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame, *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(aFrame); } - /* Preserve-3d can cause frames without a transform to get an nsDisplayTransform created, we should - * use our parent's transform here. - */ - if (!aFrame->GetStyleDisplay()->HasTransform()) { - return GetResultingTransformMatrix(aFrame->GetParent(), aOrigin - aFrame->GetPosition(), aFactor, nsnull, aOutAncestor); - } - /* Account for the -moz-transform-origin property by translating the * coordinate space to the new origin. */ diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index b29091b6c31..91a29b667f7 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2079,16 +2079,16 @@ public: * ferries the underlying frame to the nsDisplayItem constructor. */ nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, - nsDisplayList *aList) : - nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aList) + nsDisplayList *aList, PRUint32 aIndex = 0) : + nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aList), mIndex(aIndex) { MOZ_COUNT_CTOR(nsDisplayTransform); NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); } nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, - nsDisplayItem *aItem) : - nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aItem) + nsDisplayItem *aItem, PRUint32 aIndex = 0) : + nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aItem), mIndex(aIndex) { MOZ_COUNT_CTOR(nsDisplayTransform); NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); @@ -2127,6 +2127,12 @@ public: nsRegion *aVisibleRegion, const nsRect& aAllowVisibleRegionExpansion); virtual bool TryMerge(nsDisplayListBuilder *aBuilder, nsDisplayItem *aItem); + + virtual PRUint32 GetPerFrameKey() { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } + + enum { + INDEX_MAX = PR_UINT32_MAX >> nsDisplayItem::TYPE_BITS + }; const gfx3DMatrix& GetTransform(float aFactor); @@ -2205,6 +2211,7 @@ private: nsDisplayWrapList mStoredList; gfx3DMatrix mTransform; float mCachedFactor; + PRUint32 mIndex; }; /** diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 29717ff27a6..c4203a5e7a1 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1518,47 +1518,78 @@ DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, #endif static nsresult -WrapPreserve3DList(nsIFrame *aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList) +WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, PRUint32& aIndex) { + if (aIndex > nsDisplayTransform::INDEX_MAX) { + return NS_OK; + } + nsresult rv = NS_OK; nsDisplayList newList; + nsDisplayList temp; while (nsDisplayItem *item = aList->RemoveBottom()) { nsIFrame *childFrame = item->GetUnderlyingFrame(); NS_ASSERTION(childFrame, "All display items to be wrapped must have a frame!"); + + // We accumulate sequential items that aren't transforms into the 'temp' list + // and then flush this list into newList by wrapping the whole lot with a single + // nsDisplayTransform. + if (childFrame->GetParent()->Preserves3DChildren()) { switch (item->GetType()) { case nsDisplayItem::TYPE_TRANSFORM: { + if (!temp.IsEmpty()) { + newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++)); + } + newList.AppendToTop(item); break; } case nsDisplayItem::TYPE_WRAP_LIST: { + if (!temp.IsEmpty()) { + newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++)); + } nsDisplayWrapList *list = static_cast(item); - rv = WrapPreserve3DList(aFrame, aBuilder, list->GetList()); + rv = WrapPreserve3DListInternal(aFrame, aBuilder, list->GetList(), aIndex); + newList.AppendToTop(item); break; } case nsDisplayItem::TYPE_OPACITY: { + if (!temp.IsEmpty()) { + newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++)); + } nsDisplayOpacity *opacity = static_cast(item); - rv = WrapPreserve3DList(aFrame, aBuilder, opacity->GetList()); + rv = WrapPreserve3DListInternal(aFrame, aBuilder, opacity->GetList(), aIndex); + newList.AppendToTop(item); break; } default: { - item = new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item); + temp.AppendToTop(item); break; } } } else { - item = new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item); + temp.AppendToTop(item); } - if (NS_FAILED(rv) || !item) + if (NS_FAILED(rv) || !item || aIndex > nsDisplayTransform::INDEX_MAX) return rv; - - newList.AppendToTop(item); + } + + if (!temp.IsEmpty()) { + newList.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, aIndex++)); } aList->AppendToTop(&newList); return NS_OK; } +static nsresult +WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList) +{ + PRUint32 index = 0; + return WrapPreserve3DListInternal(aFrame, aBuilder, aList, index); +} + nsresult nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect,