diff --git a/gfx/layers/wr/WebRenderCommandBuilder.cpp b/gfx/layers/wr/WebRenderCommandBuilder.cpp index 45ba23e6ce34..21879161864a 100644 --- a/gfx/layers/wr/WebRenderCommandBuilder.cpp +++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp @@ -558,7 +558,8 @@ struct DIGroup { nsDisplayListBuilder* aDisplayListBuilder, wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources, Grouper* aGrouper, - nsDisplayItem* aStartItem, nsDisplayItem* aEndItem) { + nsDisplayList::iterator aStartItem, + nsDisplayList::iterator aEndItem) { GP("\n\n"); GP("Begin EndGroup\n"); @@ -654,6 +655,7 @@ struct DIGroup { RenderRootStateManager* rootManager = aWrManager->GetRenderRootStateManager(); + bool empty = aStartItem == aEndItem; if (empty) { ClearImageKey(rootManager, true); @@ -663,8 +665,8 @@ struct DIGroup { // Reset mHitInfo, it will get updated inside PaintItemRange mHitInfo = CompositorHitTestInvisibleToHit; - PaintItemRange(aGrouper, nsDisplayList::Range(aStartItem, aEndItem), - context, recorder, rootManager, aResources); + PaintItemRange(aGrouper, aStartItem, aEndItem, context, recorder, + rootManager, aResources); // XXX: set this correctly perhaps using // aItem->GetOpaqueRegion(aDisplayListBuilder, &snapped). @@ -769,14 +771,14 @@ struct DIGroup { SideBits::eNone); } - void PaintItemRange(Grouper* aGrouper, nsDisplayList::Iterator aIter, - gfxContext* aContext, + void PaintItemRange(Grouper* aGrouper, nsDisplayList::iterator aStartItem, + nsDisplayList::iterator aEndItem, gfxContext* aContext, WebRenderDrawEventRecorder* aRecorder, RenderRootStateManager* aRootManager, wr::IpcResourceUpdateQueue& aResources) { LayerIntSize size = mVisibleRect.Size(); - while (aIter.HasNext()) { - nsDisplayItem* item = aIter.GetNext(); + for (auto it = aStartItem; it != aEndItem; ++it) { + nsDisplayItem* item = *it; MOZ_ASSERT(item); BlobItemData* data = GetBlobItemData(item); @@ -949,7 +951,7 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, aContext->GetDrawTarget()->FlushItem(aItemBounds); } else { aContext->Multiply(ThebesMatrix(trans2d)); - aGroup->PaintItemRange(this, nsDisplayList::Iterator(aChildren), + aGroup->PaintItemRange(this, aChildren->begin(), aChildren->end(), aContext, aRecorder, aRootManager, aResources); } @@ -972,8 +974,8 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); aContext->GetDrawTarget()->FlushItem(aItemBounds); - aGroup->PaintItemRange(this, nsDisplayList::Iterator(aChildren), aContext, - aRecorder, aRootManager, aResources); + aGroup->PaintItemRange(this, aChildren->begin(), aChildren->end(), + aContext, aRecorder, aRootManager, aResources); aContext->GetDrawTarget()->PopLayer(); GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); @@ -989,8 +991,8 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); aContext->GetDrawTarget()->FlushItem(aItemBounds); - aGroup->PaintItemRange(this, nsDisplayList::Iterator(aChildren), aContext, - aRecorder, aRootManager, aResources); + aGroup->PaintItemRange(this, aChildren->begin(), aChildren->end(), + aContext, aRecorder, aRootManager, aResources); aContext->GetDrawTarget()->PopLayer(); GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); @@ -1003,8 +1005,8 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); aContext->GetDrawTarget()->FlushItem(aItemBounds); - aGroup->PaintItemRange(this, nsDisplayList::Iterator(aChildren), aContext, - aRecorder, aRootManager, aResources); + aGroup->PaintItemRange(this, aChildren->begin(), aChildren->end(), + aContext, aRecorder, aRootManager, aResources); aContext->GetDrawTarget()->PopLayer(); GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); @@ -1023,7 +1025,7 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey()); aContext->GetDrawTarget()->FlushItem(aItemBounds); - aGroup->PaintItemRange(this, nsDisplayList::Iterator(aChildren), + aGroup->PaintItemRange(this, aChildren->begin(), aChildren->end(), aContext, aRecorder, aRootManager, aResources); GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(), @@ -1061,8 +1063,8 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem, } default: - aGroup->PaintItemRange(this, nsDisplayList::Iterator(aChildren), aContext, - aRecorder, aRootManager, aResources); + aGroup->PaintItemRange(this, aChildren->begin(), aChildren->end(), + aContext, aRecorder, aRootManager, aResources); break; } } @@ -1186,15 +1188,18 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder, RenderRootStateManager* manager = aCommandBuilder->mManager->GetRenderRootStateManager(); - nsDisplayItem* startOfCurrentGroup = nullptr; + nsDisplayList::iterator startOfCurrentGroup = aList->end(); DIGroup* currentGroup = aGroup; // We need to track whether we have active siblings for mixed blend mode. bool encounteredActiveItem = false; - for (nsDisplayItem* item : *aList) { - if (!startOfCurrentGroup) { - startOfCurrentGroup = item; + for (auto it = aList->begin(); it != aList->end(); ++it) { + nsDisplayItem* item = *it; + MOZ_ASSERT(item); + + if (startOfCurrentGroup == aList->end()) { + startOfCurrentGroup = it; } if (IsItemProbablyActive(item, aBuilder, aResources, aSc, manager, @@ -1250,7 +1255,7 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder, currentGroup->EndGroup(aCommandBuilder->mManager, aDisplayListBuilder, aBuilder, aResources, this, startOfCurrentGroup, - item); + it); { auto spaceAndClipChain = @@ -1270,7 +1275,7 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder, sIndent--; } - startOfCurrentGroup = nullptr; + startOfCurrentGroup = aList->end(); currentGroup = &groupData->mFollowingGroup; } else { // inactive item ConstructItemInsideInactive(aCommandBuilder, aBuilder, aResources, @@ -1280,7 +1285,7 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder, currentGroup->EndGroup(aCommandBuilder->mManager, aDisplayListBuilder, aBuilder, aResources, this, startOfCurrentGroup, - nullptr); + aList->end()); } // This does a pass over the display lists and will join the display items diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 378cd8538c3c..f8a8b09efb11 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -234,7 +234,8 @@ struct RangePaintInfo { RangePaintInfo(nsRange* aRange, nsIFrame* aFrame) : mRange(aRange), - mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false) { + mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false), + mList(&mBuilder) { MOZ_COUNT_CTOR(RangePaintInfo); mBuilder.BeginFrame(); } @@ -4909,7 +4910,7 @@ UniquePtr PresShell::CreateRangePaintInfo( ViewID zoomedId = nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent()); - nsDisplayList wrapped; + nsDisplayList wrapped(&info->mBuilder); wrapped.AppendNewToTop(&info->mBuilder, rootScrollFrame, &info->mList, nullptr, zoomedId); info->mList.AppendToTop(&wrapped); @@ -5215,8 +5216,13 @@ already_AddRefed PresShell::RenderSelection( aScreenRect, aFlags); } -void AddDisplayItemToBottom(nsDisplayList* aList, nsDisplayItem* aItem) { - nsDisplayList list; +void AddDisplayItemToBottom(nsDisplayListBuilder* aBuilder, + nsDisplayList* aList, nsDisplayItem* aItem) { + if (!aItem) { + return; + } + + nsDisplayList list(aBuilder); list.AppendToTop(aItem); list.AppendToTop(aList); aList->AppendToTop(&list); @@ -5228,7 +5234,7 @@ void PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder* aBuilder, const nsRect& aBounds) { nsDisplayItem* item = MakeDisplayItem( aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115)); - AddDisplayItemToBottom(aList, item); + AddDisplayItemToBottom(aBuilder, aList, item); } static bool AddCanvasBackgroundColor(const nsDisplayList* aList, @@ -5308,7 +5314,7 @@ void PresShell::AddCanvasBackgroundColorItem( if (!addedScrollingBackgroundColor || forceUnscrolledItem) { nsDisplayItem* item = MakeDisplayItem( aBuilder, aFrame, aBounds, bgcolor); - AddDisplayItemToBottom(aList, item); + AddDisplayItemToBottom(aBuilder, aList, item); } } diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index d12edabeeb53..14c3274f1d4a 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2521,7 +2521,7 @@ bool nsLayoutUtils::GetLayerTransformForFrame(nsIFrame* aFrame, nsDisplayListBuilderMode::TransformComputation, false /*don't build caret*/); builder.BeginFrame(); - nsDisplayList list; + nsDisplayList list(&builder); nsDisplayTransform* item = MakeDisplayItem(&builder, aFrame, &list, nsRect()); MOZ_ASSERT(item); @@ -2716,7 +2716,7 @@ nsresult nsLayoutUtils::GetFramesForArea(RelativeTo aRelativeTo, nsDisplayListBuilder builder(frame, nsDisplayListBuilderMode::EventDelivery, false); builder.BeginFrame(); - nsDisplayList list; + nsDisplayList list(&builder); if (aOptions.mBits.contains(FrameForPointOption::IgnorePaintSuppression)) { builder.IgnorePaintSuppression(); @@ -3058,7 +3058,7 @@ struct TemporaryDisplayListBuilder { TemporaryDisplayListBuilder(nsIFrame* aFrame, nsDisplayListBuilderMode aBuilderMode, const bool aBuildCaret) - : mBuilder(aFrame, aBuilderMode, aBuildCaret) {} + : mBuilder(aFrame, aBuilderMode, aBuildCaret), mList(&mBuilder) {} ~TemporaryDisplayListBuilder() { mList.DeleteAll(&mBuilder); } @@ -3354,7 +3354,6 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame, } list->DeleteAll(builder); - list->RestoreState(); builder->ClearRetainedWindowRegions(); builder->ClearWillChangeBudgets(); diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index 07b9be7bd95f..759ad65549b9 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -73,7 +73,7 @@ bool nsHTMLButtonControlFrame::ShouldClipPaintingToBorderBox() { void nsHTMLButtonControlFrame::BuildDisplayList( nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { - nsDisplayList onTop; + nsDisplayList onTop(aBuilder); if (IsVisibleForPainting()) { // Clip the button itself to its border area for event hit testing. Maybe eventClipState; diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index 8e4e2f35ffc7..bef6a7f7090c 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -285,6 +285,7 @@ TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder, mBuilder(aBuilder), mBlock(aBlockFrame), mScrollableFrame(nsLayoutUtils::GetScrollableFrameFor(aBlockFrame)), + mMarkerList(aBuilder), mBlockSize(aBlockFrame->GetSize()), mBlockWM(aBlockFrame->GetWritingMode()), mAdjustForPixelSnapping(false) { diff --git a/layout/generic/ViewportFrame.cpp b/layout/generic/ViewportFrame.cpp index 45bb99b91886..5204e4939b66 100644 --- a/layout/generic/ViewportFrame.cpp +++ b/layout/generic/ViewportFrame.cpp @@ -124,7 +124,7 @@ static void BuildDisplayListForTopLayerFrame(nsDisplayListBuilder* aBuilder, nsDisplayListBuilder::AutoBuildingDisplayList buildingForChild( aBuilder, aFrame, visible, dirty); - nsDisplayList list; + nsDisplayList list(aBuilder); aFrame->BuildDisplayListForStackingContext(aBuilder, &list); aList->AppendToTop(&list); } @@ -135,7 +135,7 @@ static bool BackdropListIsOpaque(ViewportFrame* aFrame, // The common case for ::backdrop elements on the top layer is a single // fixed position container, holding an opaque background color covering // the whole viewport. - if (aList->Count() != 1 || + if (aList->Length() != 1 || aList->GetTop()->GetType() != DisplayItemType::TYPE_FIXED_POSITION) { return false; } @@ -168,7 +168,7 @@ static bool BackdropListIsOpaque(ViewportFrame* aFrame, nsDisplayWrapList* ViewportFrame::BuildDisplayListForTopLayer( nsDisplayListBuilder* aBuilder, bool* aIsOpaque) { - nsDisplayList topLayerList; + nsDisplayList topLayerList(aBuilder); nsTArray topLayer = PresContext()->Document()->GetTopLayer(); for (dom::Element* elem : topLayer) { diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index 73d311ea28ab..546717a5a17c 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -502,7 +502,7 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return false; }(); - nsDisplayList layerItems; + nsDisplayList layerItems(aBuilder); // Create separate items for each background layer. const nsStyleImageLayers& layers = bg->StyleBackground()->mImage; @@ -518,7 +518,7 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); const ActiveScrolledRoot* thisItemASR = asr; - nsDisplayList thisItemList; + nsDisplayList thisItemList(aBuilder); nsDisplayBackgroundImage::InitData bgData = nsDisplayBackgroundImage::GetInitData(aBuilder, this, i, bgRect, bg); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 7f641c73d3ae..346892e50128 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -4132,7 +4132,7 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, // Effectively we are double clipping to the viewport, at potentially // different async scales. - nsDisplayList resultList; + nsDisplayList resultList(aBuilder); set.SerializeWithCorrectZOrder(&resultList, mOuter->GetContent()); if (blendCapture.CaptureContainsBlendMode()) { diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 209b50a4039d..4e59dc4fdd17 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -2924,7 +2924,7 @@ static bool ItemParticipatesIn3DContext(nsIFrame* aAncestor, const bool isContainer = type == DisplayItemType::TYPE_WRAP_LIST || type == DisplayItemType::TYPE_CONTAINER; - if (isContainer && aItem->GetChildren()->Count() == 1) { + if (isContainer && aItem->GetChildren()->Length() == 1) { // If the wraplist has only one child item, use the type of that item. type = aItem->GetChildren()->GetBottom()->GetType(); } @@ -3131,7 +3131,6 @@ bool TryToReuseStackingContextItem(nsDisplayListBuilder* aBuilder, } nsDisplayItem* container = *res; - MOZ_ASSERT(!container->GetAbove()); MOZ_ASSERT(container->Frame() == aFrame); DL_LOGD("RDL - Found SC item %p (%s) (frame: %p)", container, container->Name(), container->Frame()); @@ -3341,7 +3340,7 @@ void nsIFrame::BuildDisplayListForStackingContext( bool usingSVGEffects = usingFilter || usingMask; nsRect visibleRectOutsideSVGEffects = visibleRect; - nsDisplayList hoistedScrollInfoItemsStorage; + nsDisplayList hoistedScrollInfoItemsStorage(aBuilder); if (usingSVGEffects) { dirtyRect = SVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect); @@ -3570,7 +3569,7 @@ void nsIFrame::BuildDisplayListForStackingContext( content = PresContext()->Document()->GetRootElement(); } - nsDisplayList resultList; + nsDisplayList resultList(aBuilder); set.SerializeWithCorrectZOrder(&resultList, content); #ifdef DEBUG @@ -3697,8 +3696,8 @@ void nsIFrame::BuildDisplayListForStackingContext( if (isTransformed && extend3DContext) { // Install dummy nsDisplayTransform as a leaf containing // descendants not participating this 3D rendering context. - nsDisplayList nonparticipants; - nsDisplayList participants; + nsDisplayList nonparticipants(aBuilder); + nsDisplayList participants(aBuilder); int index = 1; nsDisplayItem* separator = nullptr; @@ -3880,7 +3879,7 @@ void nsIFrame::BuildDisplayListForStackingContext( } nsDisplayItem* container = resultList.GetBottom(); - if (resultList.Count() > 1 || container->Frame() != this) { + if (resultList.Length() > 1 || container->Frame() != this) { container = MakeDisplayItem( aBuilder, this, containerItemASR, &resultList); } else { @@ -3918,7 +3917,7 @@ static nsDisplayItem* WrapInWrapList(nsDisplayListBuilder* aBuilder, // on which items we build, so we need to ensure that we don't transition // to/from a wrap list without invalidating correctly. bool needsWrapList = - aList->Count() > 1 || item->Frame() != aFrame || item->GetChildren(); + aList->Length() > 1 || item->Frame() != aFrame || item->GetChildren(); // If we have an explicit container item (that can't change without an // invalidation) or we're doing a full build and don't need a wrap list, then @@ -4340,8 +4339,8 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, awayFromCommonPath = true; } - nsDisplayList list; - nsDisplayList extraPositionedDescendants; + nsDisplayList list(aBuilder); + nsDisplayList extraPositionedDescendants(aBuilder); const ActiveScrolledRoot* wrapListASR; bool builtContainerItem = false; if (isStackingContext) { diff --git a/layout/generic/nsPageContentFrame.cpp b/layout/generic/nsPageContentFrame.cpp index 0ff28d386189..53703fcddc19 100644 --- a/layout/generic/nsPageContentFrame.cpp +++ b/layout/generic/nsPageContentFrame.cpp @@ -301,7 +301,7 @@ static void BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, if (!aExtraPage->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) { return; } - nsDisplayList list; + nsDisplayList list(aBuilder); aExtraPage->BuildDisplayListForStackingContext(aBuilder, &list); PruneDisplayListForExtraPage(aBuilder, aPage, &list); aList->AppendToTop(&list); @@ -332,7 +332,7 @@ void nsPageContentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayListCollection set(aBuilder); - nsDisplayList content; + nsDisplayList content(aBuilder); { const nsRect clipRect(aBuilder->ToReferenceFrame(this), GetSize()); DisplayListClipState::AutoSaveRestore clipState(aBuilder); diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index 14320e58441e..77748a8b1ad4 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -585,7 +585,7 @@ nsSize nsPageFrame::ComputePageSize() const { void nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { - nsDisplayList content; + nsDisplayList content(aBuilder); nsDisplayListSet set(&content, &content, &content, &content, &content, &content); { diff --git a/layout/generic/nsPageSequenceFrame.cpp b/layout/generic/nsPageSequenceFrame.cpp index 31a64400791b..101dd440fa60 100644 --- a/layout/generic/nsPageSequenceFrame.cpp +++ b/layout/generic/nsPageSequenceFrame.cpp @@ -731,7 +731,7 @@ void nsPageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, aBuilder->SetDisablePartialUpdates(true); DisplayBorderBackgroundOutline(aBuilder, aLists); - nsDisplayList content; + nsDisplayList content(aBuilder); { // Clear clip state while we construct the children of the diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 6b6edaed2e59..396a73c2a06d 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -310,7 +310,7 @@ static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder, nsDisplayItem* item; while ((item = aList->RemoveBottom()) != nullptr) { if (item->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) { - nsDisplayList tmpList; + nsDisplayList tmpList(aBuilder); tmpList.AppendToTop(item); item = MakeDisplayItemWithIndex( aBuilder, aFrame, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc, @@ -438,7 +438,7 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, needsOwnLayer = true; } - nsDisplayList childItems; + nsDisplayList childItems(aBuilder); { DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); diff --git a/layout/painting/RetainedDisplayListBuilder.cpp b/layout/painting/RetainedDisplayListBuilder.cpp index b3371ae38fad..4807933f5607 100644 --- a/layout/painting/RetainedDisplayListBuilder.cpp +++ b/layout/painting/RetainedDisplayListBuilder.cpp @@ -193,7 +193,7 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList( // a merge. const bool initializeOldItems = aList->mOldItems.IsEmpty(); if (initializeOldItems) { - aList->mOldItems.SetCapacity(aList->Count()); + aList->mOldItems.SetCapacity(aList->Length()); } else { MOZ_RELEASE_ASSERT(!initializeDAG); } @@ -201,7 +201,7 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList( MOZ_RELEASE_ASSERT( initializeDAG || aList->mDAG.Length() == - (initializeOldItems ? aList->Count() : aList->mOldItems.Length())); + (initializeOldItems ? aList->Length() : aList->mOldItems.Length())); nsDisplayList out; @@ -349,7 +349,6 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList( } MOZ_RELEASE_ASSERT(aList->mOldItems.Length() == aList->mDAG.Length()); - aList->RestoreState(); if (aKeepLinked) { aList->AppendToTop(&out); @@ -462,6 +461,7 @@ class MergeState { mOldDAG( std::move(*reinterpret_cast*>( &aOldList.mDAG))), + mMergedItems(aBuilder->Builder()), mOuterItem(aOuterItem), mResultIsModified(false) { mMergedDAG.EnsureCapacityFor(mOldDAG); @@ -538,7 +538,7 @@ class MergeState { } Maybe containerASRForChildren; - nsDisplayList empty; + nsDisplayList empty(mBuilder->Builder()); const bool modified = mBuilder->MergeDisplayLists( aNewItem ? aNewItem->GetChildren() : &empty, aOldItem->GetChildren(), aOutItem->GetChildren(), containerASRForChildren, aOutItem); @@ -636,10 +636,10 @@ class MergeState { ProcessOldNode(OldListIndex(i), std::move(directPredecessors)); } - RetainedDisplayList result; + RetainedDisplayList result(mBuilder->Builder()); result.AppendToTop(&mMergedItems); result.mDAG = std::move(mMergedDAG); - MOZ_RELEASE_ASSERT(result.mDAG.Length() == result.Count()); + MOZ_RELEASE_ASSERT(result.mDAG.Length() == result.Length()); return result; } @@ -1563,14 +1563,14 @@ void CollectStackingContextItems(nsDisplayListBuilder* aBuilder, int aDepth = 0, bool aParentReused = false) { nsDisplayList out; - while (nsDisplayItem* item = aList->RemoveBottom()) { + for (nsDisplayItem* item : *aList) { if (DL_LOG_TEST(LogLevel::Debug)) { DL_LOGD( "%*s Preprocessing item %p (%s) (frame: %p) " - "(children: %d) (depth: %d) (parentReused: %d)", + "(children: %zu) (depth: %d) (parentReused: %d)", aDepth, "", item, item->Name(), item->HasDeletedFrame() ? nullptr : item->Frame(), - item->GetChildren() ? item->GetChildren()->Count() : 0, aDepth, + item->GetChildren() ? item->GetChildren()->Length() : 0, aDepth, aParentReused); } @@ -1616,8 +1616,8 @@ void CollectStackingContextItems(nsDisplayListBuilder* aBuilder, } } + aList->Clear(); aList->AppendToTop(&out); - aList->RestoreState(); } } // namespace RDL @@ -1664,7 +1664,7 @@ PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate( } nsRect modifiedDirty; - nsDisplayList modifiedDL; + nsDisplayList modifiedDL(&mBuilder); nsIFrame* modifiedAGR = nullptr; PartialUpdateResult result = PartialUpdateResult::NoChange; const bool simpleUpdate = diff --git a/layout/painting/RetainedDisplayListBuilder.h b/layout/painting/RetainedDisplayListBuilder.h index d949e42e02e0..34943b3d90e4 100644 --- a/layout/painting/RetainedDisplayListBuilder.h +++ b/layout/painting/RetainedDisplayListBuilder.h @@ -177,7 +177,7 @@ struct RetainedDisplayListMetrics { struct RetainedDisplayListBuilder { RetainedDisplayListBuilder(nsIFrame* aReferenceFrame, nsDisplayListBuilderMode aMode, bool aBuildCaret) - : mBuilder(aReferenceFrame, aMode, aBuildCaret, true) {} + : mBuilder(aReferenceFrame, aMode, aBuildCaret, true), mList(&mBuilder) {} ~RetainedDisplayListBuilder() { mList.DeleteAll(&mBuilder); } nsDisplayListBuilder* Builder() { return &mBuilder; } diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 50b3c21de988..0f990e201154 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -353,11 +353,12 @@ nsDisplayWrapper* nsDisplayWrapList::CreateShallowCopy( } nsDisplayWrapList* nsDisplayListBuilder::MergeItems( - nsTArray& aItems) { + nsTArray& aItems) { // For merging, we create a temporary item by cloning the last item of the // mergeable items list. This ensures that the temporary item will have the // correct frame and bounds. - nsDisplayWrapList* last = aItems.PopLastElement(); + nsDisplayWrapList* last = aItems.PopLastElement()->AsDisplayWrapList(); + MOZ_ASSERT(last); nsDisplayWrapList* merged = last->Clone(this); MOZ_ASSERT(merged); AddTemporaryItem(merged); @@ -365,11 +366,13 @@ nsDisplayWrapList* nsDisplayListBuilder::MergeItems( // Create nsDisplayWrappers that point to the internal display lists of the // items we are merging. These nsDisplayWrappers are added to the display list // of the temporary item. - for (nsDisplayWrapList* item : Reversed(aItems)) { + for (nsDisplayItem* item : aItems) { MOZ_ASSERT(item); MOZ_ASSERT(merged->CanMerge(item)); merged->Merge(item); - merged->GetChildren()->AppendToTop(item->CreateShallowCopy(this)); + MOZ_ASSERT(item->AsDisplayWrapList()); + merged->GetChildren()->AppendToTop( + static_cast(item)->CreateShallowCopy(this)); } merged->GetChildren()->AppendToTop(last->CreateShallowCopy(this)); @@ -2322,21 +2325,6 @@ void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, gfxContext* aCtx, } } -nsDisplayItem* nsDisplayList::RemoveBottom() { - nsDisplayItem* item = mSentinel.mAbove; - if (!item) { - return nullptr; - } - mSentinel.mAbove = item->mAbove; - if (item == mTop) { - // must have been the only item - mTop = &mSentinel; - } - item->mAbove = nullptr; - mLength--; - return item; -} - void nsDisplayList::DeleteAll(nsDisplayListBuilder* aBuilder) { nsDisplayItem* item; while ((item = RemoveBottom()) != nullptr) { @@ -2696,7 +2684,8 @@ nsRect nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder) const { nsDisplayContainer::nsDisplayContainer( nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const ActiveScrolledRoot* aActiveScrolledRoot, nsDisplayList* aList) - : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) { + : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot), + mChildren(aBuilder) { MOZ_COUNT_CTOR(nsDisplayContainer); mChildren.AppendToTop(aList); UpdateBounds(aBuilder); @@ -3151,7 +3140,7 @@ AppendedBackgroundType nsDisplayBackgroundImage::AppendBackgroundItemsToTop( // An auxiliary list is necessary in case we have background blending; if that // is the case, background items need to be wrapped by a blend container to // isolate blending to the background - nsDisplayList bgItemList; + nsDisplayList bgItemList(aBuilder); // Even if we don't actually have a background color to paint, we may still // need to create an item for hit testing and we still need to create an item // for background-color animations. @@ -3260,7 +3249,7 @@ AppendedBackgroundType nsDisplayBackgroundImage::AppendBackgroundItemsToTop( willPaintBorder); } - nsDisplayList thisItemList; + nsDisplayList thisItemList(aBuilder); nsDisplayBackgroundImage::InitData bgData = nsDisplayBackgroundImage::GetInitData(aBuilder, aFrame, i, bgOriginRect, bgSC); @@ -3388,23 +3377,6 @@ static bool RoundedRectContainsRect(const nsRect& aRoundedRect, return rgn.Contains(aContainedRect); } -static void CheckForBorderItem(nsDisplayItem* aItem, uint32_t& aFlags) { - // TODO(miko): Iterating over the display list like this is suspicious. - for (nsDisplayList::Iterator it(aItem); it.HasNext(); ++it) { - nsDisplayItem* next = *it; - - if (next->GetType() == DisplayItemType::TYPE_BACKGROUND) { - continue; - } - - if (next->GetType() == DisplayItemType::TYPE_BORDER) { - aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER; - } - - break; - } -} - bool nsDisplayBackgroundImage::CanApplyOpacity( WebRenderLayerManager* aManager, nsDisplayListBuilder* aBuilder) const { // Bug 1752919: WebRender does not properly handle opacity flattening for @@ -3440,7 +3412,6 @@ bool nsDisplayBackgroundImage::CreateWebRenderCommands( uint32_t paintFlags = aDisplayListBuilder->GetBackgroundPaintFlags(); bool dummy; - CheckForBorderItem(this, paintFlags); nsCSSRendering::PaintBGParams params = nsCSSRendering::PaintBGParams::ForSingleLayer( *StyleFrame()->PresContext(), GetBounds(aDisplayListBuilder, &dummy), @@ -4592,6 +4563,7 @@ nsDisplayWrapList::nsDisplayWrapList( nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot, bool aClearClipChain) : nsPaintedDisplayItem(aBuilder, aFrame, aActiveScrolledRoot), + mList(aBuilder), mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot()), mOverrideZIndex(0), mHasZIndexOverride(false), @@ -4610,6 +4582,7 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayItem* aItem) : nsPaintedDisplayItem(aBuilder, aFrame, aBuilder->CurrentActiveScrolledRoot()), + mList(aBuilder), mOverrideZIndex(0), mHasZIndexOverride(false) { MOZ_COUNT_CTOR(nsDisplayWrapList); @@ -4855,7 +4828,7 @@ static bool CollectItemsWithOpacity(WebRenderLayerManager* aManager, nsDisplayListBuilder* aBuilder, nsDisplayList* aList, nsTArray& aArray) { - if (aList->Count() > kOpacityMaxListSize) { + if (aList->Length() > kOpacityMaxListSize) { // Exit early, since |aList| will likely contain more than // |kOpacityMaxChildCount| items. return false; @@ -4941,7 +4914,7 @@ bool nsDisplayOpacity::CanApplyToChildren(WebRenderLayerManager* aManager, * opacity. In this case the opacity item can be optimized away. */ bool nsDisplayOpacity::ApplyToMask() { - if (mList.Count() != 1) { + if (mList.Length() != 1) { return false; } @@ -5454,7 +5427,7 @@ nsDisplayFixedPosition* nsDisplayFixedPosition::CreateForFixedBackground( nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aSecondaryFrame, nsDisplayBackgroundImage* aImage, const uint16_t aIndex, const ActiveScrolledRoot* aScrollTargetASR) { - nsDisplayList temp; + nsDisplayList temp(aBuilder); temp.AppendToTop(aImage); if (aSecondaryFrame) { @@ -6027,6 +6000,7 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, const nsRect& aChildrenBuildingRect) : nsPaintedDisplayItem(aBuilder, aFrame), + mChildren(aBuilder), mTransform(Some(Matrix4x4())), mChildrenBuildingRect(aChildrenBuildingRect), mPrerenderDecision(PrerenderDecision::No), @@ -6043,6 +6017,7 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, const nsRect& aChildrenBuildingRect, PrerenderDecision aPrerenderDecision) : nsPaintedDisplayItem(aBuilder, aFrame), + mChildren(aBuilder), mChildrenBuildingRect(aChildrenBuildingRect), mPrerenderDecision(aPrerenderDecision), mIsTransformSeparator(false), @@ -6059,6 +6034,7 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, const nsRect& aChildrenBuildingRect, decltype(WithTransformGetter)) : nsPaintedDisplayItem(aBuilder, aFrame), + mChildren(aBuilder), mChildrenBuildingRect(aChildrenBuildingRect), mPrerenderDecision(PrerenderDecision::No), mIsTransformSeparator(false), @@ -6773,7 +6749,8 @@ void nsDisplayTransform::Collect3DTransformLeaves( } FlattenedDisplayListIterator iter(aBuilder, &mChildren); - while (nsDisplayItem* item = iter.GetNextItem()) { + while (iter.HasNext()) { + nsDisplayItem* item = iter.GetNextItem(); if (item->GetType() == DisplayItemType::TYPE_PERSPECTIVE) { auto* perspective = static_cast(item); if (!perspective->GetChildren()->GetTop()) { @@ -7349,9 +7326,9 @@ void nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream) { nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) - : nsPaintedDisplayItem(aBuilder, aFrame) { + : nsPaintedDisplayItem(aBuilder, aFrame), mList(aBuilder) { mList.AppendToTop(aList); - MOZ_ASSERT(mList.Count() == 1); + MOZ_ASSERT(mList.Length() == 1); MOZ_ASSERT(mList.GetTop()->GetType() == DisplayItemType::TYPE_TRANSFORM); } @@ -7816,8 +7793,8 @@ static void ComputeMaskGeometry(PaintFramesParams& aParams) { auto cssToDevScale = frame->PresContext()->CSSToDevPixelScale(); int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel(); - gfxPoint devPixelOffsetToUserSpace = nsLayoutUtils::PointToGfxPoint( - offsetToUserSpace, appUnitsPerDevPixel); + gfxPoint devPixelOffsetToUserSpace = + nsLayoutUtils::PointToGfxPoint(offsetToUserSpace, appUnitsPerDevPixel); gfxContextMatrixAutoSaveRestore matSR(&ctx); ctx.SetMatrixDouble( diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index c79517692584..d89da3d270e6 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -24,6 +24,7 @@ #include "gfxContext.h" #include "mozilla/ArenaAllocator.h" #include "mozilla/Array.h" +#include "mozilla/ArrayIterator.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" @@ -257,11 +258,17 @@ enum class nsDisplayListBuilderMode : uint8_t { GenerateGlyph, }; +using ListArenaAllocator = ArenaAllocator<4096, 8>; + +class nsDisplayItem; +class nsPaintedDisplayItem; class nsDisplayList; class nsDisplayWrapList; class nsDisplayTableBackgroundSet; class nsDisplayTableItem; +class RetainedDisplayList; + /** * This manages a display list and is passed as a parameter to * nsIFrame::BuildDisplayList. @@ -958,7 +965,7 @@ class nsDisplayListBuilder { * display item. * The display items in |aMergedItems| have to be mergeable with each other. */ - nsDisplayWrapList* MergeItems(nsTArray& aItems); + nsDisplayWrapList* MergeItems(nsTArray& aItems); /** * A helper class used to temporarily set nsDisplayListBuilder properties for @@ -1723,6 +1730,8 @@ class nsDisplayListBuilder { */ void ReuseDisplayItem(nsDisplayItem* aItem); + ListArenaAllocator& GetListAllocator() { return mListPool; } + private: bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame, const nsRect& aVisibleRect, @@ -1921,12 +1930,9 @@ class nsDisplayListBuilder { // Stores reusable items collected during display list preprocessing. nsTHashSet mReuseableItems; -}; -class nsDisplayItem; -class nsPaintedDisplayItem; -class nsDisplayList; -class RetainedDisplayList; + ArenaAllocator<4096, 8> mListPool; +}; // All types are defined in nsDisplayItemTypes.h #define NS_DISPLAY_DECL_NAME(n, e) \ @@ -2047,23 +2053,6 @@ MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsDisplayListBuilder* aBuilder, F* aFrame, std::forward(aArgs)...); } -/** - * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList. - * nsDisplayItemLink holds the link. The lists are linked from lowest to - * highest in z-order. - */ -class nsDisplayItemLink { - // This is never instantiated directly, so no need to count constructors and - // destructors. - protected: - nsDisplayItemLink() : mAbove(nullptr) {} - nsDisplayItemLink(const nsDisplayItemLink&) : mAbove(nullptr) {} - ~nsDisplayItemLink() { MOZ_RELEASE_ASSERT(!mAbove); } - nsDisplayItem* mAbove; - - friend class nsDisplayList; -}; - /* * nsDisplayItemBase is a base-class for all display items. It is mainly * responsible for handling the frame-display item 1:n relationship, as well as @@ -2077,7 +2066,7 @@ class nsDisplayItemLink { * Display items belong to a list at all times (except temporarily as they * move from one list to another). */ -class nsDisplayItem : public nsDisplayItemLink { +class nsDisplayItem { public: using Layer = layers::Layer; using LayerManager = layers::LayerManager; @@ -2106,6 +2095,12 @@ class nsDisplayItem : public nsDisplayItemLink { return nullptr; } + /** + * Checks if the given display item can be merged with this item. + * @return true if the merging is possible, otherwise false. + */ + virtual bool CanMerge(const nsDisplayItem* aItem) const { return false; } + /** * Frees the memory allocated for this display item. * The given display list builder must have allocated this display item. @@ -2706,8 +2701,6 @@ class nsDisplayItem : public nsDisplayItemLink { virtual void WriteDebugInfo(std::stringstream& aStream) {} - nsDisplayItem* GetAbove() { return mAbove; } - /** * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame()) */ @@ -2989,147 +2982,134 @@ class nsPaintedDisplayItem : public nsDisplayItem { Maybe mCacheIndex; }; +template +struct MOZ_HEAP_CLASS LinkedListNode { + explicit LinkedListNode(T aValue) : mNext(nullptr), mValue(aValue) {} + LinkedListNode* mNext; + T mValue; +}; + +template +struct LinkedListIterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + using Node = LinkedListNode; + + explicit LinkedListIterator(Node* aNode = nullptr) : mNode(aNode) {} + + LinkedListIterator& operator++() { + MOZ_ASSERT(mNode); + mNode = mNode->mNext; + return *this; + } + + bool operator==(const LinkedListIterator& aOther) const { + return mNode == aOther.mNode; + } + + bool operator!=(const LinkedListIterator& aOther) const { + return mNode != aOther.mNode; + } + + const T operator*() const { + MOZ_ASSERT(mNode); + return mNode->mValue; + } + + T operator*() { + MOZ_ASSERT(mNode); + return mNode->mValue; + } + + Node* mNode; +}; + /** * Manages a singly-linked list of display list items. * - * mSentinel is the sentinel list value, the first value in the null-terminated - * linked list of items. mTop is the last item in the list (whose 'above' - * pointer is null). This class has no virtual methods. So list objects are just - * two pointers. - * * Stepping upward through this list is very fast. Stepping downward is very * slow so we don't support it. The methods that need to step downward * (HitTest()) internally build a temporary array of all * the items while they do the downward traversal, so overall they're still * linear time. We have optimized for efficient AppendToTop() of both * items and lists, with minimal codesize. + * + * Internal linked list nodes are allocated using arena allocator. * */ class nsDisplayList { public: - class Iterator { - public: - constexpr Iterator() : mCurrent(nullptr), mEnd(nullptr) {} - ~Iterator() = default; - Iterator(const Iterator& aOther) = default; - Iterator& operator=(const Iterator& aOther) = default; + using Node = LinkedListNode; + using iterator = LinkedListIterator; + using const_iterator = iterator; - explicit Iterator(const nsDisplayList* aList) - : mCurrent(aList->GetBottom()), mEnd(nullptr) {} - explicit Iterator(nsDisplayItem* aStart) - : mCurrent(aStart), mEnd(nullptr) {} + iterator begin() { return iterator(mBottom); } + iterator end() { return iterator(nullptr); } + const_iterator begin() const { return iterator(mBottom); } + const_iterator end() const { return iterator(nullptr); } - Iterator& operator++() { - mCurrent = Next(); - return *this; - } + explicit nsDisplayList(nsDisplayListBuilder* aBuilder) + : mPool(aBuilder->GetListAllocator()) {} - nsDisplayItem* operator*() { - MOZ_ASSERT(mCurrent); - return mCurrent; - } - - bool operator==(const Iterator& aOther) const { - return mCurrent == aOther.mCurrent; - } - - bool operator!=(const Iterator& aOther) const { - return !operator==(aOther); - } - - bool HasNext() const { return mCurrent != nullptr; } - - nsDisplayItem* GetNext() { - MOZ_ASSERT(HasNext()); - auto* next = mCurrent; - operator++(); - return next; - } - - protected: - Iterator(nsDisplayItem* aStart, nsDisplayItem* aEnd) - : mCurrent(aStart), mEnd(aEnd) {} - - nsDisplayItem* Next() const { - if (!mCurrent) { - return nullptr; - } - - auto* next = mCurrent->GetAbove(); - if (next == mEnd) { - return nullptr; - } - - return next; - } - - private: - nsDisplayItem* mCurrent; - nsDisplayItem* mEnd; - }; - - class Range final : public Iterator { - public: - Range(nsDisplayItem* aStart, nsDisplayItem* aEnd) - : Iterator(aStart, aEnd) {} - }; - - Iterator begin() const { return Iterator(this); } - constexpr Iterator end() const { return Iterator(); } - - /** - * Create an empty list. - */ - nsDisplayList() : mLength(0), mForceTransparentSurface(false) { - mTop = &mSentinel; - mSentinel.mAbove = nullptr; - } + nsDisplayList() = delete; + nsDisplayList(const nsDisplayList&) = delete; + nsDisplayList& operator=(const nsDisplayList&) = delete; virtual ~nsDisplayList() { - MOZ_RELEASE_ASSERT(!mSentinel.mAbove, "Nonempty list left over?"); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + if (!mAllowNonEmptyDestruction) { + MOZ_RELEASE_ASSERT(IsEmpty(), "Nonempty list left over?"); + } +#endif + Clear(); } - nsDisplayList(nsDisplayList&& aOther) { - mForceTransparentSurface = aOther.mForceTransparentSurface; - - if (aOther.mSentinel.mAbove) { - AppendToTop(&aOther); - } else { - mTop = &mSentinel; - mLength = 0; - } + nsDisplayList(nsDisplayList&& aOther) + : mBottom(aOther.mBottom), + mTop(aOther.mTop), + mLength(aOther.mLength), + mPool(aOther.mPool) { + aOther.SetEmpty(); } nsDisplayList& operator=(nsDisplayList&& aOther) { + MOZ_RELEASE_ASSERT(&mPool == &aOther.mPool); + if (this != &aOther) { - if (aOther.mSentinel.mAbove) { - nsDisplayList tmp; - tmp.AppendToTop(&aOther); - aOther.AppendToTop(this); - AppendToTop(&tmp); - } else { - mTop = &mSentinel; - mLength = 0; - } - mForceTransparentSurface = aOther.mForceTransparentSurface; + MOZ_RELEASE_ASSERT(IsEmpty()); + mBottom = std::move(aOther.mBottom); + mTop = std::move(aOther.mTop); + mLength = std::move(aOther.mLength); + aOther.SetEmpty(); } return *this; } - nsDisplayList(const nsDisplayList&) = delete; - nsDisplayList& operator=(const nsDisplayList& aOther) = delete; - /** - * Append an item to the top of the list. The item must not currently - * be in a list and cannot be null. - */ + * Append an item to the top of the list. + **/ void AppendToTop(nsDisplayItem* aItem) { if (!aItem) { return; } - MOZ_ASSERT(!aItem->mAbove, "Already in a list!"); - mTop->mAbove = aItem; - mTop = aItem; + + auto* next = Allocate(aItem); + MOZ_ASSERT(next); + + if (IsEmpty()) { + mBottom = next; + mTop = next; + } else { + mTop->mNext = next; + mTop = next; + } + mLength++; + + MOZ_ASSERT(mBottom && mTop); + MOZ_ASSERT(mTop->mNext == nullptr); } template @@ -3144,61 +3124,84 @@ class nsDisplayList { const uint16_t aIndex, Args&&... aArgs) { nsDisplayItem* item = MakeDisplayItemWithIndex( aBuilder, aFrame, aIndex, std::forward(aArgs)...); - - if (item) { - AppendToTop(item); - } + AppendToTop(item); } /** - * Removes all items from aList and appends them to the top of this list + * Removes all items from aList and appends them to the top of this list. */ void AppendToTop(nsDisplayList* aList) { - if (aList->mSentinel.mAbove) { - mTop->mAbove = aList->mSentinel.mAbove; + MOZ_ASSERT(aList != this); + MOZ_RELEASE_ASSERT(&mPool == &aList->mPool); + + if (aList->IsEmpty()) { + return; + } + + if (IsEmpty()) { + std::swap(mBottom, aList->mBottom); + std::swap(mTop, aList->mTop); + std::swap(mLength, aList->mLength); + } else { + MOZ_ASSERT(mTop && mTop->mNext == nullptr); + mTop->mNext = aList->mBottom; mTop = aList->mTop; - aList->mTop = &aList->mSentinel; - aList->mSentinel.mAbove = nullptr; mLength += aList->mLength; - aList->mLength = 0; + + aList->SetEmpty(); } } /** - * Remove an item from the bottom of the list and return it. + * Clears the display list. */ - nsDisplayItem* RemoveBottom(); + void Clear() { + Node* current = mBottom; + Node* next = nullptr; + + while (current) { + next = current->mNext; + Deallocate(current); + current = next; + } + + SetEmpty(); + } /** * Remove all items from the list and call their destructors. */ virtual void DeleteAll(nsDisplayListBuilder* aBuilder); - /** - * @return the item at the top of the list, or null if the list is empty - */ - nsDisplayItem* GetTop() const { - return mTop != &mSentinel ? static_cast(mTop) : nullptr; - } /** * @return the item at the bottom of the list, or null if the list is empty */ - nsDisplayItem* GetBottom() const { return mSentinel.mAbove; } - bool IsEmpty() const { return mTop == &mSentinel; } + nsDisplayItem* GetBottom() const { + return mBottom ? mBottom->mValue : nullptr; + } + + /** + * @return the item at the top of the list, or null if the list is empty + */ + nsDisplayItem* GetTop() const { return mTop ? mTop->mValue : nullptr; } + + bool IsEmpty() const { return mBottom == nullptr; } /** * @return the number of items in the list */ - uint32_t Count() const { return mLength; } + size_t Length() const { return mLength; } + /** - * Stable sort the list by the z-order of GetUnderlyingFrame() on + * Stable sort the list by the z-order of Frame() on * each item. 'auto' is counted as zero. * It is assumed that the list is already in content document order. */ void SortByZOrder(); + /** * Stable sort the list by the tree order of the content of - * GetUnderlyingFrame() on each item. z-index is ignored. + * Frame() on each item. z-index is ignored. * @param aCommonAncestor a common ancestor of all the content elements * associated with the display items, for speeding up tree order * checks, or nullptr if not known; it's only a hint, if it is not an @@ -3207,15 +3210,14 @@ class nsDisplayList { void SortByContentOrder(nsIContent* aCommonAncestor); /** - * Sort the display list using a stable sort. Take care, because some of the - * items might be nsDisplayLists themselves. + * Sort the display list using a stable sort. * aComparator(Item item1, Item item2) should return true if item1 should go * before item2. * We sort the items into increasing order. */ template void Sort(const Comparator& aComparator) { - if (Count() < 2) { + if (Length() < 2) { // Only sort lists with more than one item. return; } @@ -3225,7 +3227,7 @@ class nsDisplayList { // here. AutoTArray items; - while (nsDisplayItem* item = RemoveBottom()) { + for (nsDisplayItem* item : TakeItems()) { items.AppendElement(Item(item)); } @@ -3236,10 +3238,14 @@ class nsDisplayList { } } - /** - * Returns true if any display item requires the surface to be transparent. - */ - bool NeedsTransparentSurface() const { return mForceTransparentSurface; } + nsDisplayList TakeItems() { + nsDisplayList list = std::move(*this); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + list.mAllowNonEmptyDestruction = true; +#endif + return list; + } + /** * Paint the list to the rendering context. We assume that (0,0) in aCtx * corresponds to the origin of the reference frame. For best results, @@ -3335,19 +3341,32 @@ class nsDisplayList { */ nsRect GetBuildingRect() const; - void SetNeedsTransparentSurface() { mForceTransparentSurface = true; } - - void RestoreState() { mForceTransparentSurface = false; } - private: - nsDisplayItemLink mSentinel; - nsDisplayItemLink* mTop; + inline Node* Allocate(nsDisplayItem* aItem) { + void* ptr = mPool.Allocate(sizeof(Node)); + return new (ptr) Node(aItem); + } - uint32_t mLength; + inline void Deallocate(Node* aNode) { + aNode->~Node(); + // Memory remains reserved by the arena allocator. + } - // This is set to true by FrameLayerBuilder if any display item in this - // list needs to force the surface containing this list to be transparent. - bool mForceTransparentSurface; + void SetEmpty() { + mBottom = nullptr; + mTop = nullptr; + mLength = 0; + } + + Node* mBottom = nullptr; + Node* mTop = nullptr; + size_t mLength = 0; + ListArenaAllocator& mPool; + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + // This checks that the invariant of display lists owning their items is held. + bool mAllowNonEmptyDestruction = false; +#endif }; /** @@ -3453,13 +3472,17 @@ class nsDisplayListSet { struct nsDisplayListCollection : public nsDisplayListSet { explicit nsDisplayListCollection(nsDisplayListBuilder* aBuilder) : nsDisplayListSet(&mLists[0], &mLists[1], &mLists[2], &mLists[3], - &mLists[4], &mLists[5]) {} + &mLists[4], &mLists[5]), + mLists{nsDisplayList{aBuilder}, nsDisplayList{aBuilder}, + nsDisplayList{aBuilder}, nsDisplayList{aBuilder}, + nsDisplayList{aBuilder}, nsDisplayList{aBuilder}} {} + /* explicit nsDisplayListCollection(nsDisplayListBuilder* aBuilder, nsDisplayList* aBorderBackground) : nsDisplayListSet(aBorderBackground, &mLists[1], &mLists[2], &mLists[3], &mLists[4], &mLists[5]) {} - +*/ /** * Sort all lists by content order. */ @@ -3497,29 +3520,33 @@ struct nsDisplayListCollection : public nsDisplayListSet { */ class RetainedDisplayList : public nsDisplayList { public: - RetainedDisplayList() = default; - RetainedDisplayList(RetainedDisplayList&& aOther) { - AppendToTop(&aOther); - mDAG = std::move(aOther.mDAG); - } + explicit RetainedDisplayList(nsDisplayListBuilder* aBuilder) + : nsDisplayList(aBuilder) {} + + RetainedDisplayList(RetainedDisplayList&& aOther) + : nsDisplayList(std::move(aOther)), mDAG(std::move(aOther.mDAG)) {} + + RetainedDisplayList(const RetainedDisplayList&) = delete; + RetainedDisplayList& operator=(const RetainedDisplayList&) = delete; ~RetainedDisplayList() override { MOZ_ASSERT(mOldItems.IsEmpty(), "Must empty list before destroying"); } RetainedDisplayList& operator=(RetainedDisplayList&& aOther) { - MOZ_ASSERT(!Count(), "Can only move into an empty list!"); + MOZ_ASSERT(IsEmpty(), "Can only move into an empty list!"); MOZ_ASSERT(mOldItems.IsEmpty(), "Can only move into an empty list!"); - AppendToTop(&aOther); + + nsDisplayList::operator=(std::move(aOther)); mDAG = std::move(aOther.mDAG); mOldItems = std::move(aOther.mOldItems); return *this; } RetainedDisplayList& operator=(nsDisplayList&& aOther) { - MOZ_ASSERT(!Count(), "Can only move into an empty list!"); + MOZ_ASSERT(IsEmpty(), "Can only move into an empty list!"); MOZ_ASSERT(mOldItems.IsEmpty(), "Can only move into an empty list!"); - AppendToTop(&aOther); + nsDisplayList::operator=(std::move(aOther)); return *this; } @@ -4721,6 +4748,7 @@ class nsDisplayWrapList : public nsPaintedDisplayItem { nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : nsPaintedDisplayItem(aBuilder, aFrame), + mList(aBuilder), mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot()), mOverrideZIndex(0), mHasZIndexOverride(false) { @@ -4740,6 +4768,7 @@ class nsDisplayWrapList : public nsPaintedDisplayItem { nsDisplayWrapList(nsDisplayListBuilder* aBuilder, const nsDisplayWrapList& aOther) : nsPaintedDisplayItem(aBuilder, aOther), + mList(aBuilder), mListPtr(&mList), mFrameActiveScrolledRoot(aOther.mFrameActiveScrolledRoot), mMergedFrames(aOther.mMergedFrames.Clone()), @@ -4813,12 +4842,6 @@ class nsDisplayWrapList : public nsPaintedDisplayItem { bool* aSnap) const override; Maybe IsUniform(nsDisplayListBuilder* aBuilder) const override; - /** - * Checks if the given display item can be merged with this item. - * @return true if the merging is possible, otherwise false. - */ - virtual bool CanMerge(const nsDisplayItem* aItem) const { return false; } - /** * Try to merge with the other item (which is below us in the display * list). This gets used by nsDisplayClip to coalesce clipping operations @@ -6390,12 +6413,12 @@ class nsDisplayTransform : public nsPaintedDisplayItem { void CollectSorted3DTransformLeaves(nsDisplayListBuilder* aBuilder, nsTArray& aLeaves); + mutable RetainedDisplayList mChildren; mutable Maybe mTransform; mutable Maybe mInverseTransform; // Accumulated transform of ancestors on the preserves-3d chain. UniquePtr mTransformPreserves3D; nsRect mChildrenBuildingRect; - mutable RetainedDisplayList mChildren; // The untransformed bounds of |mChildren|. nsRect mChildBounds; @@ -6693,50 +6716,58 @@ class FlattenedDisplayListIterator { public: FlattenedDisplayListIterator(nsDisplayListBuilder* aBuilder, nsDisplayList* aList) - : FlattenedDisplayListIterator(aBuilder, aList, true) {} + : mBuilder(aBuilder), mStart(aList->begin()), mEnd(aList->end()) { + ResolveFlattening(); + } - virtual bool HasNext() const { return mNext || !mStack.IsEmpty(); } + bool HasNext() const { return !AtEndOfCurrentList(); } nsDisplayItem* GetNextItem() { - if (!mNext) { - return nullptr; - } + MOZ_ASSERT(HasNext()); - nsDisplayItem* next = mNext; - mNext = next->GetAbove(); + nsDisplayItem* current = NextItem(); + Advance(); - if (mNext && next->HasChildren() && mNext->HasChildren()) { - // Since |next| and |mNext| are container items in the same list, - // merging them might be possible. - next = TryMergingFrom(next); + if (!AtEndOfCurrentList() && current->CanMerge(NextItem())) { + // Since we can merge at least two display items, create an array and + // collect mergeable display items there. + AutoTArray willMerge{current}; + + auto it = mStart; + while (it != mEnd) { + nsDisplayItem* next = *it; + if (current->CanMerge(next)) { + willMerge.AppendElement(next); + ++it; + } else { + break; + } + } + mStart = it; + + current = mBuilder->MergeItems(willMerge); } ResolveFlattening(); - - return next; + return current; } - nsDisplayItem* PeekNext() { return mNext; } - protected: - FlattenedDisplayListIterator(nsDisplayListBuilder* aBuilder, - nsDisplayList* aList, - const bool aResolveFlattening) - : mBuilder(aBuilder), mNext(aList->GetBottom()) { - if (aResolveFlattening) { - // This is done conditionally in case subclass overrides - // ShouldFlattenNextItem(). - ResolveFlattening(); - } + void Advance() { ++mStart; } + + bool AtEndOfNestedList() const { + return AtEndOfCurrentList() && mStack.Length() > 0; } - virtual void EnterChildList(nsDisplayItem* aContainerItem) {} - virtual void ExitChildList() {} + bool AtEndOfCurrentList() const { return mStart == mEnd; } - bool AtEndOfNestedList() const { return !mNext && mStack.Length() > 0; } + nsDisplayItem* NextItem() { + MOZ_ASSERT(HasNext()); + return *mStart; + } - virtual bool ShouldFlattenNextItem() { - return mNext && mNext->ShouldFlattenAway(mBuilder); + bool ShouldFlattenNextItem() { + return HasNext() && NextItem()->ShouldFlattenAway(mBuilder); } void ResolveFlattening() { @@ -6745,60 +6776,36 @@ class FlattenedDisplayListIterator { // item, or the very end of the outer list. while (AtEndOfNestedList() || ShouldFlattenNextItem()) { if (AtEndOfNestedList()) { - ExitChildList(); - - // We reached the end of the list, pop the next item from the stack. - mNext = mStack.PopLastElement(); + // We reached the end of the list, pop the next list from the stack. + std::tie(mStart, mEnd) = mStack.PopLastElement(); } else { - EnterChildList(mNext); + // The next item wants to be flattened. This means that we will skip the + // flattened item and directly iterate over its sublist. + MOZ_ASSERT(ShouldFlattenNextItem()); - // This item wants to be flattened. Store the next item on the stack, - // and use the first item in the child list instead. - mStack.AppendElement(mNext->GetAbove()); - mNext = mNext->GetChildren()->GetBottom(); + nsDisplayList* sublist = NextItem()->GetChildren(); + MOZ_ASSERT(sublist); + + // Skip the flattened item. + Advance(); + + // Store the current position on the stack. + if (!AtEndOfCurrentList()) { + mStack.AppendElement(std::make_pair(mStart, mEnd)); + } + + // Iterate over the sublist. + mStart = sublist->begin(); + mEnd = sublist->end(); } } } - /** - * Tries to merge display items starting from |aCurrent|. - * Updates the internal pointer to the next display item. - */ - nsDisplayItem* TryMergingFrom(nsDisplayItem* aCurrent) { - MOZ_ASSERT(aCurrent); - MOZ_ASSERT(aCurrent->GetAbove()); - - nsDisplayWrapList* current = aCurrent->AsDisplayWrapList(); - nsDisplayWrapList* next = mNext->AsDisplayWrapList(); - - if (!current || !next) { - // Either the current or the next item do not support merging. - return aCurrent; - } - - // Attempt to merge |next| with |current|. - if (current->CanMerge(next)) { - // Merging is possible, collect all the successive mergeable items. - AutoTArray willMerge{current}; - - do { - willMerge.AppendElement(next); - mNext = next->GetAbove(); - next = mNext ? mNext->AsDisplayWrapList() : nullptr; - } while (next && current->CanMerge(next)); - - current = mBuilder->MergeItems(willMerge); - } - - // Here |mNext| will be either the first item that could not be merged with - // |current|, or nullptr. - return current; - } - private: nsDisplayListBuilder* mBuilder; - nsDisplayItem* mNext; - AutoTArray mStack; + nsDisplayList::iterator mStart; + nsDisplayList::iterator mEnd; + nsTArray> mStack; }; class PaintTelemetry { diff --git a/layout/svg/SVGForeignObjectFrame.cpp b/layout/svg/SVGForeignObjectFrame.cpp index 040696454cb5..3e9fadfff875 100644 --- a/layout/svg/SVGForeignObjectFrame.cpp +++ b/layout/svg/SVGForeignObjectFrame.cpp @@ -154,7 +154,7 @@ void SVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, if (!static_cast(GetContent())->HasValidDimensions()) { return; } - nsDisplayList newList; + nsDisplayList newList(aBuilder); nsDisplayListSet set(&newList, &newList, &newList, &newList, &newList, &newList); DisplayOutline(aBuilder, set); diff --git a/layout/svg/SVGOuterSVGFrame.cpp b/layout/svg/SVGOuterSVGFrame.cpp index 3fa92544ae08..a31c92216ede 100644 --- a/layout/svg/SVGOuterSVGFrame.cpp +++ b/layout/svg/SVGOuterSVGFrame.cpp @@ -997,7 +997,7 @@ void SVGOuterSVGAnonChildFrame::BuildDisplayList( // inside the nsDisplayTransform for our viewbox transform. The // nsDisplaySVGWrapper's reference frame is this frame, because this frame // always returns true from IsSVGTransformed. - nsDisplayList newList; + nsDisplayList newList(aBuilder); nsDisplayListSet set(&newList, &newList, &newList, &newList, &newList, &newList); BuildDisplayListForNonBlockChildren(aBuilder, set); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 15fc496fcf49..77f3e4de1332 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -7520,7 +7520,9 @@ void nsDisplayTableItem::ComputeInvalidationRegion( nsDisplayTableBackgroundSet::nsDisplayTableBackgroundSet( nsDisplayListBuilder* aBuilder, nsIFrame* aTable) - : mBuilder(aBuilder) { + : mBuilder(aBuilder), + mColGroupBackgrounds(aBuilder), + mColBackgrounds(aBuilder) { mPrevTableBackgroundSet = mBuilder->SetTableBackgroundSet(this); mozilla::DebugOnly reference = mBuilder->FindReferenceFrameFor(aTable, &mToReferenceFrame); diff --git a/layout/xul/nsBoxFrame.cpp b/layout/xul/nsBoxFrame.cpp index 3eb01fe2ce68..09368d9260e6 100644 --- a/layout/xul/nsBoxFrame.cpp +++ b/layout/xul/nsBoxFrame.cpp @@ -961,7 +961,7 @@ void nsBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // and merge them into a single Content() list. This can cause us // to violate CSS stacking order, but forceLayer is a magic // XUL-only extension anyway. - nsDisplayList masterList; + nsDisplayList masterList(aBuilder); masterList.AppendToTop(tempLists.BorderBackground()); masterList.AppendToTop(tempLists.BlockBorderBackgrounds()); masterList.AppendToTop(tempLists.Floats()); diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp index 878ede10c0b0..7ac99a6f11c5 100644 --- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -330,7 +330,7 @@ void nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox clip( aBuilder, this, clipFlags); - nsDisplayList list; + nsDisplayList list(aBuilder); list.AppendNewToTop(aBuilder, this); CreateOwnLayerIfNeeded(aBuilder, &list, diff --git a/layout/xul/nsSliderFrame.cpp b/layout/xul/nsSliderFrame.cpp index 96d1d8af1798..86e7f5e6c7dd 100644 --- a/layout/xul/nsSliderFrame.cpp +++ b/layout/xul/nsSliderFrame.cpp @@ -500,7 +500,7 @@ void nsSliderFrame::BuildDisplayListForChildren( // This is a bit of a hack. Collect up all descendant display items // and merge them into a single Content() list. - nsDisplayList masterList; + nsDisplayList masterList(aBuilder); masterList.AppendToTop(tempLists.BorderBackground()); masterList.AppendToTop(tempLists.BlockBorderBackgrounds()); masterList.AppendToTop(tempLists.Floats());