Bug 1234485 - Part 8. Implement ContainerState::SetupMaskLayerForCSSMask.
MozReview-Commit-ID: Gu1u4WvL2Cy
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1253,17 +1253,19 @@ protected:
* a layer doesn't exist.
*
* Since mask layers can exist either on the layer directly, or as a side-
* attachment to FrameMetrics (for ancestor scrollframe clips), we key the
* recycle operation on both the originating layer and the mask layer's
* index in the layer, if any.
*/
struct MaskLayerKey;
- already_AddRefed<ImageLayer> CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey);
+ already_AddRefed<ImageLayer>
+ CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey,
+ mozilla::function<void(Layer* aLayer)> aSetUserData);
/**
* Grabs all PaintedLayers and ColorLayers from the ContainerLayer and makes them
* available for recycling.
*/
void CollectOldLayers();
/**
* If aItem used to belong to a PaintedLayer, invalidates the area of
* aItem in that layer. If aNewLayer is a PaintedLayer, invalidates the area of
@@ -1346,16 +1348,22 @@ protected:
* add it to |aLayer|'s ancestor mask layers, returning an index into
* the array of ancestor mask layers. Returns an empty Maybe if
* |aClip| does not have rounded corners, or if no mask layer could
* be created.
*/
Maybe<size_t> SetupMaskLayerForScrolledClip(Layer* aLayer,
const DisplayItemClip& aClip);
+ /*
+ * Create/find a mask layer with suitable size for aMaskItem to paint
+ * css-positioned-masking onto.
+ */
+ void SetupMaskLayerForCSSMask(Layer* aLayer, nsDisplayMask* aMaskItem);
+
already_AddRefed<Layer> CreateMaskLayer(
Layer *aLayer, const DisplayItemClip& aClip,
const Maybe<size_t>& aForAncestorMaskLayer,
uint32_t aRoundedRectClipCount = UINT32_MAX);
bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
AnimatedGeometryRoot **aAnimatedGeometryRoot);
@@ -2222,29 +2230,30 @@ ContainerState::CreateOrRecycleImageLaye
// Remove other layer types we might have stored for this PaintedLayer
data->mColorLayer = nullptr;
}
return layer.forget();
}
already_AddRefed<ImageLayer>
-ContainerState::CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey)
+ContainerState::CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey,
+ mozilla::function<void(Layer* aLayer)> aSetUserData)
{
RefPtr<ImageLayer> result = mRecycledMaskImageLayers.Get(aKey);
if (result) {
mRecycledMaskImageLayers.Remove(aKey);
aKey.mLayer->ClearExtraDumpInfo();
// XXX if we use clip on mask layers, null it out here
} else {
// Create a new layer
result = mManager->CreateImageLayer();
if (!result)
return nullptr;
- result->SetUserData(&gMaskLayerUserData, new MaskLayerUserData());
+ aSetUserData(result);
}
return result.forget();
}
static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
/**
@@ -3860,16 +3869,73 @@ ContainerState::SetupMaskLayerForScrolle
aLayer->AddAncestorMaskLayer(maskLayer);
return maskLayerIndex;
}
// Fall through to |return Nothing()|.
}
return Nothing();
}
+void
+ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
+ nsDisplayMask* aMaskItem)
+{
+ MOZ_ASSERT(mManager->IsCompositingCheap());
+
+ RefPtr<ImageLayer> maskLayer =
+ CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, Nothing()),
+ [](Layer* aMaskLayer)
+ {
+ aMaskLayer->SetUserData(&gCSSMaskLayerUserData,
+ new CSSMaskLayerUserData());
+ }
+ );
+
+ CSSMaskLayerUserData* oldUserData =
+ static_cast<CSSMaskLayerUserData*>(maskLayer->GetUserData(&gCSSMaskLayerUserData));
+
+ bool snap;
+ nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
+ CSSMaskLayerUserData newUserData(aMaskItem->Frame(), bounds);
+ if (*oldUserData == newUserData) {
+ aLayer->SetMaskLayer(maskLayer);
+ return;
+ }
+
+ const nsIFrame* frame = aMaskItem->Frame();
+ int32_t A2D = frame->PresContext()->AppUnitsPerDevPixel();
+ Rect devBounds = NSRectToRect(bounds, A2D);
+ uint32_t maxSize = mManager->GetMaxTextureSize();
+ gfx::Size surfaceSize(std::min<gfx::Float>(devBounds.Width(), maxSize),
+ std::min<gfx::Float>(devBounds.Height(), maxSize));
+ IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width),
+ NSToIntCeil(surfaceSize.height));
+
+ if (surfaceSizeInt.IsEmpty()) {
+ return;
+ }
+
+ MaskImageData imageData(surfaceSizeInt, mManager);
+ RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
+ if (!dt || !dt->IsValid()) {
+ NS_WARNING("Could not create DrawTarget for mask layer.");
+ return;
+ }
+
+ RefPtr<ImageContainer> imgContainer =
+ imageData.CreateImageAndImageContainer();
+ if (!imgContainer) {
+ return;
+ }
+ maskLayer->SetContainer(imgContainer);
+
+ *oldUserData = newUserData;
+ aLayer->SetMaskLayer(maskLayer);
+}
+
/*
* Iterate through the non-clip items in aList and its descendants.
* For each item we compute the effective clip rect. Each item is assigned
* to a layer. We invalidate the areas in PaintedLayers where an item
* has moved from one PaintedLayer to another. Also,
* aState->mInvalidPaintedContent is invalidated in every PaintedLayer.
* We set the clip rect for items that generated their own layer, and
* create a mask layer to do any rounded rect clipping.
@@ -6141,19 +6207,33 @@ ContainerState::SetupMaskLayer(Layer *aL
}
already_AddRefed<Layer>
ContainerState::CreateMaskLayer(Layer *aLayer,
const DisplayItemClip& aClip,
const Maybe<size_t>& aForAncestorMaskLayer,
uint32_t aRoundedRectClipCount)
{
+ // aLayer will never be the container layer created by an nsDisplayMask
+ // because nsDisplayMask propagates the DisplayItemClip to its contents
+ // and is not clipped itself.
+ // This assertion will fail if that ever stops being the case.
+ MOZ_ASSERT(!aLayer->GetUserData(&gCSSMaskLayerUserData),
+ "A layer contains round clips should not have css-mask on it.");
+
// check if we can re-use the mask layer
MaskLayerKey recycleKey(aLayer, aForAncestorMaskLayer);
- RefPtr<ImageLayer> maskLayer = CreateOrRecycleMaskImageLayerFor(recycleKey);
+ RefPtr<ImageLayer> maskLayer =
+ CreateOrRecycleMaskImageLayerFor(recycleKey,
+ [](Layer* aMaskLayer)
+ {
+ aMaskLayer->SetUserData(&gMaskLayerUserData,
+ new MaskLayerUserData());
+ }
+ );
MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer);
MaskLayerUserData newData;
aClip.AppendRoundedRects(&newData.mRoundedClipRects, aRoundedRectClipCount);
newData.mScaleX = mParameters.mXScale;
newData.mScaleY = mParameters.mYScale;
newData.mOffset = mParameters.mOffset;
newData.mAppUnitsPerDevPixel = mContainerFrame->PresContext()->AppUnitsPerDevPixel();
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -19,16 +19,17 @@
#include "Layers.h"
#include "LayerUserData.h"
class nsDisplayListBuilder;
class nsDisplayList;
class nsDisplayItem;
class gfxContext;
class nsDisplayItemGeometry;
+class nsDisplayMask;
namespace mozilla {
class DisplayItemScrollClip;
namespace layers {
class ContainerLayer;
class LayerManager;
class BasicLayerManager;
class PaintedLayer;