Bug 785333 - Keep track of merged frames with all display items. r=roc

This changes the display-item storage to store layers against the underlying
frame and all merged frames of an item (and similarly, to retrieve them against
all frames of an item).
This commit is contained in:
Chris Lord 2012-08-24 16:17:22 +01:00
parent 8646631b2f
commit f1d99acd96
2 changed files with 74 additions and 29 deletions

View File

@ -882,7 +882,7 @@ FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKe
}
Layer*
FrameLayerBuilder::GetOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
{
// If we need to build a new layer tree, then just refuse to recycle
// anything.
@ -903,6 +903,31 @@ FrameLayerBuilder::GetOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
return nullptr;
}
Layer*
FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem)
{
uint32_t key = aItem->GetPerFrameKey();
nsIFrame* frame = aItem->GetUnderlyingFrame();
if (frame) {
Layer* oldLayer = GetOldLayerForFrame(frame, key);
if (oldLayer) {
return oldLayer;
}
}
nsAutoTArray<nsIFrame*,4> mergedFrames;
aItem->GetMergedFrames(&mergedFrames);
for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
Layer* oldLayer = GetOldLayerForFrame(mergedFrames[i], key);
if (oldLayer) {
return oldLayer;
}
}
return nullptr;
}
/* static */ Layer*
FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
{
@ -1862,11 +1887,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
void
ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer)
{
nsIFrame* f = aItem->GetUnderlyingFrame();
NS_ASSERTION(f, "Display items that render using Thebes must have a frame");
uint32_t key = aItem->GetPerFrameKey();
NS_ASSERTION(key, "Display items that render using Thebes must have a key");
Layer* oldLayer = mLayerBuilder->GetOldLayerFor(f, key);
NS_ASSERTION(aItem->GetUnderlyingFrame(), "Display items that render using Thebes must have a frame");
NS_ASSERTION(aItem->GetPerFrameKey(), "Display items that render using Thebes must have a key");
Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem);
if (!oldLayer) {
// Nothing to do here, this item didn't have a layer before
return;
@ -1938,6 +1961,19 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
}
}
void
FrameLayerBuilder::AddLayerDisplayItemForFrame(Layer* aLayer,
nsIFrame* aFrame,
PRUint32 aDisplayItemKey,
LayerState aLayerState)
{
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aFrame);
if (entry) {
entry->mContainerLayerGeneration = mContainerLayerGeneration;
entry->mData.AppendElement(DisplayItemData(aLayer, aDisplayItemKey, aLayerState, mContainerLayerGeneration));
}
}
void
FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
nsDisplayItem* aItem,
@ -1947,10 +1983,13 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
return;
nsIFrame* f = aItem->GetUnderlyingFrame();
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(f);
entry->mContainerLayerGeneration = mContainerLayerGeneration;
if (entry) {
entry->mData.AppendElement(DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState, mContainerLayerGeneration));
PRUint32 key = aItem->GetPerFrameKey();
AddLayerDisplayItemForFrame(aLayer, f, key, aLayerState);
nsAutoTArray<nsIFrame*,4> mergedFrames;
aItem->GetMergedFrames(&mergedFrames);
for (PRUint32 i = 0; i < mergedFrames.Length(); ++i) {
AddLayerDisplayItemForFrame(aLayer, mergedFrames[i], key, aLayerState);
}
}
@ -2285,22 +2324,13 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
nsRefPtr<ContainerLayer> 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<nsIFrame*,4> mergedFrames;
aContainerItem->GetMergedFrames(&mergedFrames);
for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
oldLayer = GetOldLayerFor(mergedFrames[i], containerDisplayItemKey);
if (oldLayer) {
break;
}
}
}
// Using GetOldLayerFor will search merged frames, as well as the underlying
// frame. The underlying frame can change when a page scrolls, so this
// avoids layer recreation in the situation that a new underlying frame is
// picked for a layer.
Layer* oldLayer = aContainerItem ?
GetOldLayerFor(aContainerItem) :
GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
if (oldLayer) {
NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
@ -2475,7 +2505,7 @@ FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
nsIFrame* f = aItem->GetUnderlyingFrame();
NS_ASSERTION(f, "Can only call GetLeafLayerFor on items that have a frame");
Layer* layer = GetOldLayerFor(f, aItem->GetPerFrameKey());
Layer* layer = GetOldLayerForFrame(f, aItem->GetPerFrameKey());
if (!layer)
return nullptr;
if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {

View File

@ -268,7 +268,7 @@ public:
/* These are only in the public section because they need
* to be called by file-scope helper functions in FrameLayerBuilder.cpp.
*/
/**
* Record aItem as a display item that is rendered by aLayer.
*/
@ -276,6 +276,14 @@ public:
nsDisplayItem* aItem,
LayerState aLayerState);
/**
* Record aFrame as a frame that is rendered by an item on aLayer.
*/
void AddLayerDisplayItemForFrame(Layer* aLayer,
nsIFrame* aFrame,
PRUint32 aDisplayItemKey,
LayerState aLayerState);
/**
* Record aItem as a display item that is rendered by the ThebesLayer
* aLayer, with aClipRect, where aContainerLayerFrame is the frame
@ -296,7 +304,14 @@ public:
* This could be a dedicated layer for the display item, or a ThebesLayer
* that renders many display items.
*/
Layer* GetOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
Layer* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey);
/**
* Calls GetOldLayerForFrame on the underlying frame of the display item,
* and each subsequent merged frame if no layer is found for the underlying
* frame.
*/
Layer* GetOldLayerFor(nsDisplayItem* aItem);
static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
/**