Bug 1166301 - If APZ is enabled, clip fixed background images at the layer level rather than the display item level. r=mattwoodrow
This ensures that regions beyond the clip are painted, and async scrolling can reveal them by moving the layer-level clip.
This patch also ensures that we continue creating mask layers for fixed background layers correctly, where appropriate.
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3170,17 +3170,29 @@ void ContainerState::FinishPaintedLayerD
}
userData->mForcedBackgroundColor = backgroundColor;
userData->mFontSmoothingBackgroundColor = data->mFontSmoothingBackgroundColor;
// use a mask layer for rounded rect clipping.
// data->mCommonClipCount may be -1 if we haven't put any actual
// drawable items in this layer (i.e. it's only catching events).
- int32_t commonClipCount = std::max(0, data->mCommonClipCount);
+ 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()) {
+ data->mLayer->SetClipRect(Some(ViewAs<ParentLayerPixel>(ScaleToNearestPixels(data->mItemClip.GetClipRect()))));
+ // 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.
+ commonClipCount = data->mItemClip.GetRoundedRectCount();
+ } else {
+ commonClipCount = std::max(0, data->mCommonClipCount);
+ }
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);
@@ -3779,16 +3791,29 @@ ContainerState::ProcessDisplayItems(nsDi
DisplayItemClip clip =
GetScrollClipIntersection(mBuilder, realAnimatedGeometryRootOfItem,
animatedGeometryRoot,
IsCaretWithCustomClip(item, itemType));
clip.IntersectWith(item->GetClip());
item->SetClip(mBuilder, clip);
}
+ bool shouldFixToViewport = !animatedGeometryRoot->GetParent() &&
+ item->ShouldFixToViewport(mManager);
+
+ // For items that are fixed to the viewport, remove their clip at the
+ // display item level because additional areas could be brought into
+ // view by async scrolling. Save the clip so we can set it on the layer
+ // instead later.
+ DisplayItemClip fixedToViewportClip = DisplayItemClip::NoClip();
+ if (shouldFixToViewport) {
+ fixedToViewportClip = item->GetClip();
+ item->SetClip(mBuilder, DisplayItemClip::NoClip());
+ }
+
bool snap;
nsRect itemContent = item->GetBounds(mBuilder, &snap);
if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
nsDisplayLayerEventRegions* eventRegions =
static_cast<nsDisplayLayerEventRegions*>(item);
itemContent = eventRegions->GetHitRegionBounds(mBuilder, &snap);
}
nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
@@ -3816,19 +3841,16 @@ ContainerState::ProcessDisplayItems(nsDi
((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, bounds);
#endif
// We haven't computed visibility at this point, so item->GetVisibleRect()
// is just the dirty rect that item was initialized with. We intersect it
// with the clipped item bounds to get a tighter visible rect.
nsIntRect itemVisibleRect = itemDrawRect.Intersect(
ScaleToOutsidePixels(item->GetVisibleRect(), false));
- bool shouldFixToViewport = !animatedGeometryRoot->GetParent() &&
- item->ShouldFixToViewport(mManager);
-
if (maxLayers != -1 && layerCount >= maxLayers) {
forceInactive = true;
}
// Assign the item to a layer
if (layerState == LAYER_ACTIVE_FORCE ||
(layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) ||
(!forceInactive &&
@@ -4040,16 +4062,23 @@ ContainerState::ProcessDisplayItems(nsDi
itemClip, aList,
&paintedLayerData->mHideAllLayersBelow,
&paintedLayerData->mOpaqueForAnimatedGeometryRootParent);
MOZ_ASSERT(nsIntRegion(itemDrawRect).Contains(opaquePixels));
opaquePixels.AndWith(itemVisibleRect);
paintedLayerData->Accumulate(this, item, opaquePixels,
itemVisibleRect, itemClip, layerState);
+ // If we removed the clip from the display item above because it's
+ // fixed to the viewport, save it on the PaintedLayerData so we can
+ // set it on the layer later.
+ if (fixedToViewportClip.HasClip()) {
+ paintedLayerData->mItemClip = fixedToViewportClip;
+ }
+
if (!paintedLayerData->mLayer) {
// Try to recycle the old layer of this display item.
nsRefPtr<PaintedLayer> layer =
AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft);
if (layer) {
paintedLayerData->mLayer = layer;
NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,