diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index d9673a4c5370..da3c7124c734 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -23,6 +23,7 @@ #include "ImageContainer.h" #include "ActiveLayerTracker.h" #include "gfx2DGlue.h" +#include "mozilla/LookAndFeel.h" #include "GeckoProfiler.h" #include "mozilla/gfx/Tools.h" @@ -521,7 +522,7 @@ public: * This is the method that actually walks a display list and builds * the child layers. */ - void ProcessDisplayItems(const nsDisplayList& aList, uint32_t aFlags); + void ProcessDisplayItems(nsDisplayList* aList, uint32_t aFlags); /** * This finalizes all the open ThebesLayers by popping every element off * mThebesLayerDataStack, then sets the children of the container layer @@ -2410,6 +2411,31 @@ ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList, return false; } +/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem + * is an overlay scrollbar item for the same scroll frame. + */ +static bool +IsScrollLayerItemAndOverlayScrollbarForScrollFrame( + nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem) +{ + if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER && + aPotentialScrollbarItem && + aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER && + LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) { + nsDisplayScrollLayer* scrollItem = + static_cast(aPotentialScrollItem); + nsDisplayOwnLayer* layerItem = + static_cast(aPotentialScrollbarItem); + if ((layerItem->GetFlags() & + (nsDisplayOwnLayer::VERTICAL_SCROLLBAR | + nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) && + layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) { + return true; + } + } + return false; +} + /* * Iterate through the non-clip items in aList and its descendants. * For each item we compute the effective clip rect. Each item is assigned @@ -2425,7 +2451,7 @@ ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList, * of ContainerState::Finish. */ void -ContainerState::ProcessDisplayItems(const nsDisplayList& aList, +ContainerState::ProcessDisplayItems(nsDisplayList* aList, uint32_t aFlags) { PROFILER_LABEL("ContainerState", "ProcessDisplayItems", @@ -2438,7 +2464,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // layer, so we need to choose which active scrolled root to use for all // items. if (aFlags & NO_COMPONENT_ALPHA) { - if (ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) { + if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot)) { topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame); } } @@ -2446,7 +2472,42 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, int32_t maxLayers = nsDisplayItem::MaxActiveLayers(); int layerCount = 0; - for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { + nsDisplayList savedItems; + nsDisplayItem* item; + while ((item = aList->RemoveBottom()) != nullptr) { + // Peek ahead to the next item and try merging with it or swapping with it + // if necessary. + nsDisplayItem* aboveItem; + while ((aboveItem = aList->GetBottom()) != nullptr) { + if (aboveItem->TryMerge(mBuilder, item)) { + aList->RemoveBottom(); + item->~nsDisplayItem(); + item = aboveItem; + } else if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(aboveItem, item)) { + // If an overlay scrollbar item is between a scroll layer item and the + // other scroll layer items that we need to merge with just move the + // scrollbar item up, that way it will be on top of the scrolled content + // and we can try to merge all the scroll layer items. + aList->RemoveBottom(); + aList->AppendToBottom(item); + item = aboveItem; + } else { + break; + } + } + + nsDisplayList* itemSameCoordinateSystemChildren + = item->GetSameCoordinateSystemChildren(); + if (itemSameCoordinateSystemChildren) { + if (item->ShouldFlattenAway(mBuilder)) { + aList->AppendToBottom(itemSameCoordinateSystemChildren); + item->~nsDisplayItem(); + continue; + } + } + + savedItems.AppendToTop(item); + NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item), "items in a container layer should all have the same app units per dev pixel"); @@ -2667,6 +2728,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, } } } + + aList->AppendToTop(&savedItems); } void @@ -3313,7 +3376,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, LayerManager* aManager, nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem, - const nsDisplayList& aChildren, + nsDisplayList* aChildren, const ContainerLayerParameters& aParameters, const gfx3DMatrix* aTransform, uint32_t aFlags) @@ -3377,7 +3440,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, // early exit because later, invalidation will walk up the frame tree to // determine which thebes layer gets invalidated. Since an empty layer // should never have anything to paint, it should never be invalidated. - NS_ASSERTION(aChildren.IsEmpty(), "Should have no children"); + NS_ASSERTION(aChildren->IsEmpty(), "Should have no children"); return containerLayer.forget(); } @@ -3445,7 +3508,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, break; } - NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds"); + NS_ASSERTION(bounds.IsEqualInterior(aChildren->GetBounds(aBuilder)), "Wrong bounds"); pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y)); if (aParameters.mAncestorClipRect && !(aFlags & CONTAINER_NOT_CLIPPED_BY_ANCESTORS)) { SetVisibleRegionForLayer(containerLayer, nsIntRegion(pixBounds), @@ -3455,7 +3518,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, } // Make sure that rounding the visible region out didn't add any area // we won't paint - if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) { + if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) { bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale); if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) { // Clear CONTENT_COMPONENT_ALPHA diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index fad65d41d791..7131b3588af1 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -207,13 +207,14 @@ public: * is set based on what's in the layer. * The container layer is transformed by aTransform (if non-null), and * the result is transformed by the scale factors in aContainerParameters. + * aChildren is modified due to display item merging and flattening. */ already_AddRefed BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, LayerManager* aManager, nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem, - const nsDisplayList& aChildren, + nsDisplayList* aChildren, const ContainerLayerParameters& aContainerParameters, const gfx3DMatrix* aTransform, uint32_t aFlags = 0); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 7b48fbd9d987..84ecb7429e92 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1232,10 +1232,9 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, - uint32_t aFlags) const { + uint32_t aFlags) { PROFILER_LABEL("nsDisplayList", "PaintRoot", js::ProfileEntry::Category::GRAPHICS); - PaintForFrame(aBuilder, aCtx, aBuilder->RootReferenceFrame(), aFlags); } @@ -1247,7 +1246,7 @@ void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, nsIFrame* aForFrame, - uint32_t aFlags) const { + uint32_t aFlags) { NS_ASSERTION(mDidComputeVisibility, "Must call ComputeVisibility before calling Paint"); @@ -1319,7 +1318,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, ContainerLayerParameters containerParameters (presShell->GetXResolution(), presShell->GetYResolution()); nsRefPtr root = layerBuilder-> - BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this, + BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, this, containerParameters, nullptr); nsIDocument* document = nullptr; @@ -3288,7 +3287,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; } nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, aContainerParameters, nullptr); if (!container) return nullptr; @@ -3451,7 +3450,7 @@ nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder, newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, newContainerParameters, nullptr); if (!container) { return nullptr; @@ -3528,7 +3527,7 @@ nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder* aBuilder, newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, newContainerParameters, nullptr); if (!container) { return nullptr; @@ -3573,7 +3572,7 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) { nsRefPtr layer = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, aContainerParameters, nullptr); if (mFlags & VERTICAL_SCROLLBAR) { layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL); @@ -3896,7 +3895,7 @@ nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) { nsRefPtr layer = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, aContainerParameters, nullptr); nsRect viewport = mScrollFrame->GetRect() - @@ -4800,7 +4799,7 @@ already_AddRefed nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu uint32_t flags = ShouldPrerenderTransformedContent(aBuilder, mFrame, false) ? FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0; nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetChildren(), + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mStoredList.GetChildren(), aContainerParameters, &newTransformMatrix, flags); if (!container) { @@ -5324,7 +5323,7 @@ nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder, } nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, newContainerParameters, nullptr); return container.forget(); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index f3ca92732f57..3ee49bde7809 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1681,13 +1681,13 @@ public: PAINT_COMPRESSED = 0x10 }; void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, - uint32_t aFlags) const; + uint32_t aFlags); /** * Like PaintRoot, but used for internal display sublists. * aForFrame is the frame that the list is associated with. */ void PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, - nsIFrame* aForFrame, uint32_t aFlags) const; + nsIFrame* aForFrame, uint32_t aFlags); /** * Get the bounds. Takes the union of the bounds of all children. */