From 88afa39f1cccfda9dc48367a1b2dd72e23a990ce Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 9 Jun 2014 16:48:00 +1200 Subject: [PATCH] Bug 1022612. Part 10: Implement merging and flattening in ProcessDisplayItems. r=mattwoodrow BuildContainerLayerFor now has to be able to mutate the passed-in display item list. --HG-- extra : rebase_source : 6a9727998a5ffb01896a4a2bbdd8d30a24c89dcd --- layout/base/FrameLayerBuilder.cpp | 79 +++++++++++++++++++++++++++---- layout/base/FrameLayerBuilder.h | 3 +- layout/base/nsDisplayList.cpp | 21 ++++---- layout/base/nsDisplayList.h | 4 +- 4 files changed, 85 insertions(+), 22 deletions(-) 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 3e9683e640a6..eb230ee38b7c 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1235,10 +1235,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); } @@ -1250,7 +1249,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"); @@ -1322,7 +1321,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; @@ -3291,7 +3290,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; @@ -3454,7 +3453,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; @@ -3531,7 +3530,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; @@ -3576,7 +3575,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); @@ -3899,7 +3898,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() - @@ -4803,7 +4802,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) { @@ -5327,7 +5326,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. */