Bug 1166301 - If APZ is enabled, clip fixed background images at the layer level rather than the display item level. r=mattwoodrow draft
authorBotond Ballo <botond@mozilla.com>
Mon, 31 Aug 2015 21:09:45 -0400
changeset 289356 0fbcfff395aa85064555ff72c7003552e5830d16
parent 289355 e5de8cbf78ac8bdb8bdcc764c2bab0e8f400ffaf
child 289357 93841515f598bbc4c3cb5372aea2b989ee78c29f
push id4975
push userbballo@mozilla.com
push dateTue, 01 Sep 2015 01:57:17 +0000
reviewersmattwoodrow
bugs1166301
milestone43.0a1
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.
layout/base/FrameLayerBuilder.cpp
--- 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,