Bug 785333 - Make sure layers are only associated with a single frame. r=roc

Use Layer user-data to ensure that a Layer doesn't end up being found multiple
times for different frames during construction.
This commit is contained in:
Chris Lord 2012-08-29 11:53:34 +01:00
parent be2d43f5f8
commit 8751a59609
2 changed files with 51 additions and 13 deletions

View File

@ -546,6 +546,16 @@ struct MaskLayerUserData : public LayerUserData
float mScaleX, mScaleY;
};
/*
* User data to track the owning frame of a layer during construction.
*/
struct LayerOwnerUserData : public LayerUserData
{
LayerOwnerUserData(nsIFrame* aOwnerFrame) : mOwnerFrame(aOwnerFrame) {}
nsIFrame* mOwnerFrame;
};
/**
* The address of gThebesDisplayItemLayerUserData is used as the user
* data key for ThebesLayers created by FrameLayerBuilder.
@ -580,6 +590,12 @@ uint8_t gLayerManagerUserData;
* The user data is a MaskLayerUserData.
*/
uint8_t gMaskLayerUserData;
/**
* The address of gLayerOwnerUserData is used as the user
* data key for a Layer's owner frame during layer-building.
* The user data is a LayerOwnerUserData.
*/
uint8_t gLayerOwnerUserData;
/**
* Helper functions for getting user data and casting it to the correct type.
@ -691,32 +707,41 @@ FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
}
/**
* A helper function to remove the mThebesLayerItems entries for every
* layer in aLayer's subtree.
* A helper function to remove the mThebesLayerItems entries and
* layer ownership user-data for every layer in aLayer's subtree.
*/
void
FrameLayerBuilder::RemoveThebesItemsForLayerSubtree(Layer* aLayer)
FrameLayerBuilder::RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer,
bool aRemoveThebesItems,
bool aRemoveOwnerData)
{
if (aRemoveOwnerData) {
// Remove the layer owner flag so that this layer can be recovered by other
// frames in future layer tree constructions.
aLayer->RemoveUserData(&gLayerOwnerUserData);
}
ThebesLayer* thebes = aLayer->AsThebesLayer();
if (thebes) {
mThebesLayerItems.RemoveEntry(thebes);
if (aRemoveThebesItems) {
mThebesLayerItems.RemoveEntry(thebes);
}
return;
}
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
RemoveThebesItemsForLayerSubtree(child);
RemoveThebesItemsAndOwnerDataForLayerSubtree(child, aRemoveThebesItems,
aRemoveOwnerData);
}
}
void
FrameLayerBuilder::DidEndTransaction(LayerManager* aManager)
{
if (aManager != mRetainingManager) {
Layer* root = aManager->GetRoot();
if (root) {
RemoveThebesItemsForLayerSubtree(root);
}
Layer* root = aManager->GetRoot();
if (root) {
RemoveThebesItemsAndOwnerDataForLayerSubtree(root, aManager != mRetainingManager, true);
}
GetMaskLayerImageCache()->Sweep();
@ -896,8 +921,13 @@ FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKe
for (uint32_t i = 0; i < array->Length(); ++i) {
if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
Layer* layer = array->ElementAt(i).mLayer;
if (layer->Manager() == mRetainingManager)
return layer;
if (layer->Manager() == mRetainingManager) {
LayerOwnerUserData* layerOwner = static_cast<LayerOwnerUserData*>
(layer->GetUserData(&gLayerOwnerUserData));
if (!layerOwner || layerOwner->mOwnerFrame == aFrame) {
return layer;
}
}
}
}
return nullptr;
@ -2352,6 +2382,12 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
return nullptr;
}
// This layer is owned by this frame for this building phase, don't let
// it be found by another frame due to its old underlying frame or merged
// frames. This flag will be cleared in FrameLayerBuilder::DidEndTransaction
containerLayer->SetUserData(&gLayerOwnerUserData,
new LayerOwnerUserData(aContainerFrame));
if (aContainerItem &&
aContainerItem->GetLayerState(aBuilder, aManager, aParameters) == LAYER_ACTIVE_EMPTY) {
// Empty layers only have metadata and should never have display items. We

View File

@ -599,7 +599,9 @@ public:
}
protected:
void RemoveThebesItemsForLayerSubtree(Layer* aLayer);
void RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer,
bool aRemoveThebesItems,
bool aRemoveOwnerData);
static void SetAndClearInvalidRegion(DisplayItemDataEntry* aEntry);
static PLDHashOperator UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,