diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 5bb066aec19f..4203f7ab46c5 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -152,6 +152,7 @@ public: // will work. mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() && !mParameters.AllowResidualTranslation(); + mRecycledMaskImageLayers.Init(); CollectOldLayers(); } @@ -347,6 +348,12 @@ protected: * more recyclable ImageLayers. */ already_AddRefed CreateOrRecycleImageLayer(); + /** + * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a + * mask layer which has been used for aLayer before), or create one if such + * a layer doesn't exist. + */ + already_AddRefed CreateOrRecycleMaskImageLayerFor(Layer* aLayer); /** * Grabs all ThebesLayers and ColorLayers from the ContainerLayer and makes them * available for recycling. @@ -421,6 +428,8 @@ protected: nsTArray > mRecycledThebesLayers; nsTArray > mRecycledColorLayers; nsTArray > mRecycledImageLayers; + nsDataHashtable, nsRefPtr > + mRecycledMaskImageLayers; PRUint32 mNextFreeRecycledThebesLayer; PRUint32 mNextFreeRecycledColorLayer; PRUint32 mNextFreeRecycledImageLayer; @@ -809,9 +818,10 @@ ContainerState::CreateOrRecycleColorLayer() // Recycle a layer layer = mRecycledColorLayers[mNextFreeRecycledColorLayer]; ++mNextFreeRecycledColorLayer; - // Clear clip rect so we don't accidentally stay clipped. We will - // reapply any necessary clipping. + // Clear clip rect and mask layer so we don't accidentally stay clipped. + // We will reapply any necessary clipping. layer->SetClipRect(nsnull); + layer->SetMaskLayer(nsnull); } else { // Create a new layer layer = mManager->CreateColorLayer(); @@ -831,9 +841,10 @@ ContainerState::CreateOrRecycleImageLayer() // Recycle a layer layer = mRecycledImageLayers[mNextFreeRecycledImageLayer]; ++mNextFreeRecycledImageLayer; - // Clear clip rect so we don't accidentally stay clipped. We will - // reapply any necessary clipping. + // Clear clip rect and mask layer so we don't accidentally stay clipped. + // We will reapply any necessary clipping. layer->SetClipRect(nsnull); + layer->SetMaskLayer(nsnull); } else { // Create a new layer layer = mManager->CreateImageLayer(); @@ -845,6 +856,24 @@ ContainerState::CreateOrRecycleImageLayer() return layer.forget(); } +already_AddRefed +ContainerState::CreateOrRecycleMaskImageLayerFor(Layer* aLayer) +{ + nsRefPtr result = mRecycledMaskImageLayers.Get(aLayer); + if (result) { + mRecycledMaskImageLayers.Remove(aLayer); + // if we use clip on mask layers, null it out here + } else { + // Create a new layer + result = mManager->CreateImageLayer(); + if (!result) + return nsnull; + result->SetUserData(&gMaskLayerUserData, new MaskLayerUserData()); + } + + return result.forget(); +} + static nsIntPoint GetTranslationForThebesLayer(ThebesLayer* aLayer) { @@ -867,9 +896,10 @@ ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot) // Recycle a layer layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer]; ++mNextFreeRecycledThebesLayer; - // Clear clip rect so we don't accidentally stay clipped. We will - // reapply any necessary clipping. + // Clear clip rect and mask layer so we don't accidentally stay clipped. + // We will reapply any necessary clipping. layer->SetClipRect(nsnull); + layer->SetMaskLayer(nsnull); data = static_cast (layer->GetUserData(&gThebesDisplayItemLayerUserData)); @@ -1730,6 +1760,8 @@ ContainerState::CollectOldLayers() { for (Layer* layer = mContainerLayer->GetFirstChild(); layer; layer = layer->GetNextSibling()) { + NS_ASSERTION(!layer->HasUserData(&gMaskLayerUserData), + "Mask layer in layer tree; could not be recycled."); if (layer->HasUserData(&gColorLayerUserData)) { mRecycledColorLayers.AppendElement(static_cast(layer)); } else if (layer->HasUserData(&gImageLayerUserData)) { @@ -1738,6 +1770,12 @@ ContainerState::CollectOldLayers() NS_ASSERTION(layer->AsThebesLayer(), "Wrong layer type"); mRecycledThebesLayers.AppendElement(static_cast(layer)); } + + if (Layer* maskLayer = layer->GetMaskLayer()) { + NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE, + "Could not recycle mask layer, unsupported layer type."); + mRecycledMaskImageLayers.Put(layer, static_cast(maskLayer)); + } } } @@ -1933,6 +1971,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, containerLayer = static_cast(oldLayer); // Clear clip rect; the caller will set it if necessary. containerLayer->SetClipRect(nsnull); + containerLayer->SetMaskLayer(nsnull); } } } @@ -2036,6 +2075,7 @@ FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder, } // Clear clip rect; the caller is responsible for setting it. layer->SetClipRect(nsnull); + layer->SetMaskLayer(nsnull); return layer; }