From 0c22df2d8c0d908515e1c2fbd637751adb3b4fcc Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 21 Feb 2014 14:11:17 +1300 Subject: [PATCH] Bug 969354. Track which ThebesLayers contain items which returned true from ShouldFixToViewport, and make sure each such item gets its own ThebesLayer. r=mattwoodrow --HG-- extra : rebase_source : 629f91869bd4c4ad2e4e17c40c5fe0311532fb67 --- layout/base/FrameLayerBuilder.cpp | 46 +++++++++++++++++++++++++------ layout/base/nsDisplayList.h | 3 +- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index eeb759183906..19f448a53f50 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -237,11 +237,13 @@ public: mAnimatedGeometryRoot(nullptr), mReferenceFrame(nullptr), mLayer(nullptr), mIsSolidColorInVisibleRegion(false), + mSingleItemFixedToViewport(false), mNeedComponentAlpha(false), mForceTransparentSurface(false), mImage(nullptr), mCommonClipCount(-1), - mAllDrawingAbove(false) {} + mAllDrawingAbove(false) + {} /** * Record that an item has been added to the ThebesLayer, so we * need to update our regions. @@ -384,6 +386,11 @@ public: * True if every pixel in mVisibleRegion will have color mSolidColor. */ bool mIsSolidColorInVisibleRegion; + /** + * True if the layer contains exactly one item that returned true for + * ShouldFixToViewport. + */ + bool mSingleItemFixedToViewport; /** * True if there is any text visible in the layer that's over * transparent pixels in the layer. @@ -607,10 +614,13 @@ protected: * has a displayport. Updates *aVisibleRegion to be the intersection of * aDrawRegion and the displayport, and updates *aIsSolidColorInVisibleRegion * (if non-null) to false if the visible region grows. + * aDisplayItemFixedToViewport is true if the layer contains a single display + * item which returned true for ShouldFixToViewport. * This can return the actual viewport frame for layers whose display items * are directly on the viewport (e.g. background-attachment:fixed backgrounds). */ const nsIFrame* FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot, + bool aDisplayItemFixedToViewport, const nsIntRegion& aDrawRegion, nsIntRegion* aVisibleRegion, bool* aIsSolidColorInVisibleRegion = nullptr); @@ -641,11 +651,15 @@ protected: * @param aOpaqueRect if non-null, a region of the display item that is opaque * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect * will be painted with aSolidColor by the item + * @param aShouldFixToViewport if true, aAnimatedGeometryRoot is the viewport + * and we will be adding fixed-pos metadata for this layer because the + * display item returned true from ShouldFixToViewport. */ ThebesLayerData* FindThebesLayerFor(nsDisplayItem* aItem, const nsIntRect& aVisibleRect, const nsIFrame* aAnimatedGeometryRoot, - const nsPoint& aTopLeft); + const nsPoint& aTopLeft, + bool aShouldFixToViewport); ThebesLayerData* GetTopThebesLayerData() { return mThebesLayerDataStack.IsEmpty() ? nullptr @@ -1662,6 +1676,7 @@ ThebesLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder) const nsIFrame* ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot, + bool aDisplayItemFixedToViewport, const nsIntRegion& aDrawRegion, nsIntRegion* aVisibleRegion, bool* aIsSolidColorInVisibleRegion) @@ -1676,7 +1691,7 @@ ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryR const nsIFrame* result = nullptr; nsRect displayPort; - if (viewport == aAnimatedGeometryRoot && + if (viewport == aAnimatedGeometryRoot && aDisplayItemFixedToViewport && nsLayoutUtils::ViewportHasDisplayPort(presContext, &displayPort)) { // Probably a background-attachment:fixed item result = viewport; @@ -1791,6 +1806,7 @@ ContainerState::PopThebesLayerData() const nsIFrame* fixedPosFrameForLayerData = FindFixedPosFrameForLayerData(data->mAnimatedGeometryRoot, + data->mSingleItemFixedToViewport, data->mDrawRegion, &data->mVisibleRegion, &data->mIsSolidColorInVisibleRegion); @@ -2071,7 +2087,7 @@ ThebesLayerData::Accumulate(ContainerState* aState, mDrawRegion.Or(mDrawRegion, aDrawRect); mDrawRegion.SimplifyOutward(4); } - + bool snap; nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap); if (!opaque.IsEmpty()) { @@ -2123,14 +2139,21 @@ ThebesLayerData* ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, const nsIntRect& aVisibleRect, const nsIFrame* aActiveScrolledRoot, - const nsPoint& aTopLeft) + const nsPoint& aTopLeft, + bool aShouldFixToViewport) { int32_t i; int32_t lowestUsableLayerWithScrolledRoot = -1; int32_t topmostLayerWithScrolledRoot = -1; for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) { ThebesLayerData* data = mThebesLayerDataStack[i]; - if (data->IsBelow(aVisibleRect)) { + // ThebesLayers for items returning true from ShouldFixToViewport should + // not be added to (or have content moved below them), + // since they will receive special treatment for async scrolling. + // If the item is going to be fixed to the viewport, don't let it combine + // with any existing layer. + if (data->IsBelow(aVisibleRect) || data->mSingleItemFixedToViewport || + aShouldFixToViewport) { ++i; break; } @@ -2170,6 +2193,7 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, thebesLayerData->mLayer = layer; thebesLayerData->mAnimatedGeometryRoot = aActiveScrolledRoot; thebesLayerData->mReferenceFrame = aItem->ReferenceFrame(); + thebesLayerData->mSingleItemFixedToViewport = aShouldFixToViewport; NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???"); *mNewChildLayers.AppendElement() = layer.forget(); @@ -2350,6 +2374,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, topLeft = animatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame); } } + bool shouldFixToViewport = !animatedGeometryRoot->GetParent() && + item->ShouldFixToViewport(mBuilder); if (maxLayers != -1 && layerCount >= maxLayers) { forceInactive = true; @@ -2403,8 +2429,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, "Should never have created a dedicated Thebes layer!"); nsIntRegion visibleRegion(itemVisibleRect); - const nsIFrame* fixedPosFrame = FindFixedPosFrameForLayerData(animatedGeometryRoot, - nsIntRegion(itemDrawRect), &visibleRegion); + const nsIFrame* fixedPosFrame = + FindFixedPosFrameForLayerData(animatedGeometryRoot, shouldFixToViewport, + nsIntRegion(itemDrawRect), &visibleRegion); if (fixedPosFrame) { itemVisibleRect = visibleRegion.GetBounds(); } @@ -2487,7 +2514,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, dummy); } else { ThebesLayerData* data = - FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft); + FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft, + shouldFixToViewport); if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) { nsDisplayLayerEventRegions* eventRegions = diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index b59d803f929d..3a84d06c169f 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -990,8 +990,7 @@ public: { return false; } /** * @return true if the contents of this item are rendered fixed relative - * to the nearest viewport *and* they cover the viewport's scrollport. - * Only return true if the contents actually vary when scrolling in the viewport. + * to the nearest viewport. */ virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) { return false; }