Bug 1267438 - For fixed backgrounds, use the scrolled clip rather than the isClipFixed=false annotation. r=mstange
MozReview-Commit-ID: 9STe7ypglpP
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1344,16 +1344,26 @@ protected:
* aRoundedRectClipCount is used when building mask layers for PaintedLayers,
* SetupMaskLayer will build a mask layer for only the first
* aRoundedRectClipCount rounded rects in aClip
*/
void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
const nsIntRegion& aLayerVisibleRegion,
uint32_t aRoundedRectClipCount = UINT32_MAX);
+ /**
+ * If |aClip| has rounded corners, create a mask layer for them, and
+ * 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);
+
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);
@@ -3114,27 +3124,33 @@ void ContainerState::FinishPaintedLayerD
// drawable items in this layer (i.e. it's only catching events).
int32_t commonClipCount;
// If the layer contains a single item fixed to the viewport, we removed
// its clip in ProcessDisplayItems() and saved it to set on the layer instead.
// Set the clip on the layer now.
if (data->mSingleItemFixedToViewport && data->mItemClip.HasClip()) {
nsIntRect layerClipRect = ScaleToNearestPixels(data->mItemClip.GetClipRect());
layerClipRect.MoveBy(mParameters.mOffset);
- data->mLayer->SetClipRect(Some(ViewAs<ParentLayerPixel>(layerClipRect)));
+ // The clip from such an item becomes part of the layer's scrolled clip,
+ // and the associated mask layer one of the layer's "ancestor mask layers".
+ LayerClip scrolledClip;
+ scrolledClip.SetClipRect(ViewAs<ParentLayerPixel>(layerClipRect));
+ scrolledClip.SetMaskLayerIndex(
+ SetupMaskLayerForScrolledClip(data->mLayer, data->mItemClip));
+ data->mLayer->SetScrolledClip(Some(scrolledClip));
// There is only one item, so all of the clips are in common to all items.
// data->mCommonClipCount will be zero because we removed the clip from
// the display item. (It could also be -1 if we're inside an inactive
// layer tree in which we don't call UpdateCommonClipCount() at all.)
MOZ_ASSERT(data->mCommonClipCount == -1 || data->mCommonClipCount == 0);
commonClipCount = data->mItemClip.GetRoundedRectCount();
} else {
commonClipCount = std::max(0, data->mCommonClipCount);
+ SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion, commonClipCount);
}
- SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion, commonClipCount);
// copy commonClipCount to the entry
FrameLayerBuilder::PaintedLayerItemsEntry* entry = mLayerBuilder->
GetPaintedLayerItemsEntry(static_cast<PaintedLayer*>(layer.get()));
entry->mCommonClipCount = commonClipCount;
} else {
// mask layer for image and color layers
SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion);
}
@@ -3623,16 +3639,32 @@ InnermostScrollClipApplicableToAGR(const
if (nsLayoutUtils::IsAncestorFrameCrossDoc(scrolledFrame, *aAnimatedGeometryRoot)) {
// scrollClip and all its ancestors are applicable.
return scrollClip;
}
}
return nullptr;
}
+Maybe<size_t>
+ContainerState::SetupMaskLayerForScrolledClip(Layer* aLayer,
+ const DisplayItemClip& aClip)
+{
+ if (aClip.GetRoundedRectCount() > 0) {
+ Maybe<size_t> maskLayerIndex = Some(aLayer->GetAncestorMaskLayerCount());
+ if (RefPtr<Layer> maskLayer = CreateMaskLayer(aLayer, aClip, maskLayerIndex,
+ aClip.GetRoundedRectCount())) {
+ aLayer->AddAncestorMaskLayer(maskLayer);
+ return maskLayerIndex;
+ }
+ // Fall through to |return Nothing()|.
+ }
+ return Nothing();
+}
+
/*
* 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.
@@ -3984,27 +4016,45 @@ ContainerState::ProcessDisplayItems(nsDi
// Update that layer's clip and visible rects.
NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
"We shouldn't have a FrameLayerBuilder-managed layer here!");
NS_ASSERTION(layerClip.HasClip() ||
layerClip.GetRoundedRectCount() == 0,
"If we have rounded rects, we must have a clip rect");
+
// It has its own layer. Update that layer's clip and visible rects.
+
if (layerClip.HasClip()) {
- ownLayer->SetClipRect(Some(layerClipRect));
+ if (shouldFixToViewport) {
+ // For layers fixed to the viewport, the clip becomes part of the
+ // layer's scrolled clip.
+ LayerClip scrolledClip;
+ scrolledClip.SetClipRect(layerClipRect);
+ if (layerClip.IsRectClippedByRoundedCorner(itemContent)) {
+ scrolledClip.SetMaskLayerIndex(
+ SetupMaskLayerForScrolledClip(ownLayer.get(), layerClip));
+ }
+ ownLayer->SetScrolledClip(Some(scrolledClip));
+ } else {
+ ownLayer->SetClipRect(Some(layerClipRect));
+
+ // rounded rectangle clipping using mask layers
+ // (must be done after visible rect is set on layer)
+ if (layerClip.IsRectClippedByRoundedCorner(itemContent)) {
+ SetupMaskLayer(ownLayer, layerClip, itemVisibleRect);
+ }
+ }
} else {
- ownLayer->SetClipRect(Nothing());
- }
-
- // rounded rectangle clipping using mask layers
- // (must be done after visible rect is set on layer)
- if (layerClip.IsRectClippedByRoundedCorner(itemContent)) {
- SetupMaskLayer(ownLayer, layerClip, itemVisibleRect);
+ if (shouldFixToViewport) {
+ ownLayer->SetScrolledClip(Nothing());
+ } else {
+ ownLayer->SetClipRect(Nothing());
+ }
}
ContainerLayer* oldContainer = ownLayer->GetParent();
if (oldContainer && oldContainer != mContainerLayer) {
oldContainer->RemoveChild(ownLayer);
}
NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
"Layer already in list???");
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -4885,17 +4885,17 @@ nsDisplayFixedPosition::BuildLayer(nsDis
// For background-attachment:fixed items, the anchor point is always the
// top-left of the viewport currently.
viewportFrame = fixedFrame;
}
// The anchorRect top-left is always the viewport top-left.
anchorRect.MoveTo(viewportFrame->GetOffsetToCrossDoc(ReferenceFrame()));
nsLayoutUtils::SetFixedPositionLayerData(layer,
- viewportFrame, anchorRect, fixedFrame, presContext, aContainerParameters, !mIsFixedBackground);
+ viewportFrame, anchorRect, fixedFrame, presContext, aContainerParameters, true);
return layer.forget();
}
bool nsDisplayFixedPosition::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != TYPE_FIXED_POSITION)
return false;
// Items with the same fixed position frame can be merged.