From 30b4deab7ad8d344e2e1ba6ce11da458f720c88b Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Fri, 24 Aug 2012 16:17:22 +0100 Subject: [PATCH] Bug 785333 - Store container layers against merged frames. r=roc As well as storing the container layer against the underlying frame of the container item, store it against its merged frames as well. In addition, check for old container layers against merged frames when building a container layer. This protects against losing the layer when the underlying frame of a container item changes to either a new frame or an existing, merged frame. --- layout/base/FrameLayerBuilder.cpp | 23 +++++++++++++++++++++++ layout/base/nsDisplayList.cpp | 8 -------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index a5ac196347f..55b7d429126 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2286,6 +2286,22 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, nsRefPtr containerLayer; if (aManager == mRetainingManager) { Layer* oldLayer = GetOldLayerFor(aContainerFrame, containerDisplayItemKey); + + // If a layer isn't found, see if we can find one for a merged frame. The + // underlying frame can change when a page scrolls, this avoids layer + // recreation in the situation that a new underlying frame is picked for + // a layer. + if (!oldLayer && aContainerItem) { + nsAutoTArray mergedFrames; + aContainerItem->GetMergedFrames(&mergedFrames); + for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { + oldLayer = GetOldLayerFor(mergedFrames[i], containerDisplayItemKey); + if (oldLayer) { + break; + } + } + } + if (oldLayer) { NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager"); if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) { @@ -2379,6 +2395,13 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, nsIFrame* mergedFrame = mergedFrames[i]; DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame); if (entry) { + // Append the container layer so we don't regenerate layers when + // the underlying frame of an item changes to one of the existing + // merged frames. + entry->mData.AppendElement( + DisplayItemData(containerLayer, containerDisplayItemKey, + LAYER_ACTIVE, mContainerLayerGeneration)); + // Ensure that UpdateDisplayItemDataForFrame recognizes that we // still have a container layer associated with this frame. entry->mIsSharingContainerLayer = true; diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 8443a2c2b87..776032d2a66 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2701,14 +2701,6 @@ nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder* aBuilder, props.Set(nsIFrame::ScrollLayerCount(), reinterpret_cast(GetScrollLayerCount() - 1)); - // Swap frames with the other item before doing MergeFrom. - // XXX - This ensures that the frame associated with a scroll layer after - // merging is the first, rather than the last. This tends to change less, - // ensuring we're more likely to retain the associated gfx layer. - // See Bug 729534 and Bug 731641. - nsIFrame* tmp = mFrame; - mFrame = other->mFrame; - other->mFrame = tmp; MergeFromTrackingMergedFrames(other); return true; }