Bug 1722346 - Only append to the end/top of the display list r=mstange

Differential Revision: https://phabricator.services.mozilla.com/D137894
This commit is contained in:
Miko Mynttinen 2022-02-21 16:50:22 +00:00
parent ce80a4e5b7
commit ad4c9a454d
6 changed files with 63 additions and 116 deletions

View File

@ -5215,12 +5215,20 @@ already_AddRefed<SourceSurface> PresShell::RenderSelection(
aScreenRect, aFlags);
}
void AddDisplayItemToBottom(nsDisplayList* aList, nsDisplayItem* aItem) {
nsDisplayList list;
list.AppendToTop(aItem);
list.AppendToTop(aList);
aList->AppendToTop(&list);
}
void PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList,
nsIFrame* aFrame,
const nsRect& aBounds) {
aList->AppendNewToBottom<nsDisplaySolidColor>(aBuilder, aFrame, aBounds,
NS_RGB(115, 115, 115));
nsDisplayItem* item = MakeDisplayItem<nsDisplaySolidColor>(
aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115));
AddDisplayItemToBottom(aList, item);
}
static bool AddCanvasBackgroundColor(const nsDisplayList* aList,
@ -5274,16 +5282,15 @@ void PresShell::AddCanvasBackgroundColorItem(
// color background behind a scrolled transparent background. Instead,
// we'll try to move the color background into the scrolled content
// by making nsDisplayCanvasBackground paint it.
// If we're only adding an unscrolled item, then pretend that we've
// already done it.
bool addedScrollingBackgroundColor =
!!(aFlags & AddCanvasBackgroundColorFlags::AppendUnscrolledOnly);
if (!aFrame->GetParent() && !addedScrollingBackgroundColor) {
bool addedScrollingBackgroundColor = false;
if (!aFrame->GetParent()) {
nsIScrollableFrame* sf =
aFrame->PresShell()->GetRootScrollFrameAsScrollable();
if (sf) {
nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
if (canvasFrame && canvasFrame->IsVisibleForPainting()) {
// TODO: We should be able to set canvas background color during display
// list building to avoid calling this function.
addedScrollingBackgroundColor = AddCanvasBackgroundColor(
aList, canvasFrame, bgcolor, mHasCSSBackgroundColor);
}
@ -5299,8 +5306,9 @@ void PresShell::AddCanvasBackgroundColorItem(
nsLayoutUtils::UsesAsyncScrolling(aFrame) && NS_GET_A(bgcolor) == 255;
if (!addedScrollingBackgroundColor || forceUnscrolledItem) {
aList->AppendNewToBottom<nsDisplaySolidColor>(aBuilder, aFrame, aBounds,
bgcolor);
nsDisplayItem* item = MakeDisplayItem<nsDisplaySolidColor>(
aBuilder, aFrame, aBounds, bgcolor);
AddDisplayItemToBottom(aList, item);
}
}

View File

@ -181,8 +181,6 @@ enum class ResolutionChangeOrigin : uint8_t {
enum class AddCanvasBackgroundColorFlags {
None = 0,
ForceDraw = 1 << 0,
AddForSubDocument = 1 << 1,
AppendUnscrolledOnly = 1 << 2,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AddCanvasBackgroundColorFlags)

View File

@ -502,6 +502,8 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return false;
}();
nsDisplayList layerItems;
// Create separate items for each background layer.
const nsStyleImageLayers& layers = bg->StyleBackground()->mImage;
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
@ -573,7 +575,7 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder, this, i + 1, &thisItemList, layers.mLayers[i].mBlendMode,
thisItemASR, true);
}
aLists.BorderBackground()->AppendToTop(&thisItemList);
layerItems.AppendToTop(&thisItemList);
}
bool hasFixedBottomLayer =
@ -591,10 +593,12 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// interleaving the two with a scrolled background color.
// PresShell::AddCanvasBackgroundColorItem makes sure there always is a
// non-scrolled background color item at the bottom.
aLists.BorderBackground()
->AppendNewToBottom<nsDisplayCanvasBackgroundColor>(aBuilder, this);
aLists.BorderBackground()->AppendNewToTop<nsDisplayCanvasBackgroundColor>(
aBuilder, this);
}
aLists.BorderBackground()->AppendToTop(&layerItems);
if (needBlendContainer) {
const ActiveScrolledRoot* containerASR = contASRTracker.GetContainerASR();
DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder);

View File

@ -498,11 +498,9 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// happens after we've built the list so that
// AddCanvasBackgroundColorItem can monkey with the contents if
// necessary.
AddCanvasBackgroundColorFlags flags =
AddCanvasBackgroundColorFlags::ForceDraw |
AddCanvasBackgroundColorFlags::AddForSubDocument;
presShell->AddCanvasBackgroundColorItem(
aBuilder, &childItems, frame, bounds, NS_RGBA(0, 0, 0, 0), flags);
aBuilder, &childItems, frame, bounds, NS_RGBA(0, 0, 0, 0),
AddCanvasBackgroundColorFlags::ForceDraw);
}
}
}

View File

@ -334,35 +334,46 @@ static bool GenerateAndPushTextMask(nsIFrame* aFrame, gfxContext* aContext,
return true;
}
nsDisplayWrapper* nsDisplayWrapList::CreateShallowCopy(
nsDisplayListBuilder* aBuilder) {
const nsDisplayWrapList* wrappedItem = AsDisplayWrapList();
MOZ_ASSERT(wrappedItem);
// Create a new nsDisplayWrapList using a copy-constructor. This is done
// to preserve the information about bounds.
nsDisplayWrapper* wrapper =
new (aBuilder) nsDisplayWrapper(aBuilder, *wrappedItem);
wrapper->SetType(nsDisplayWrapper::ItemType());
MOZ_ASSERT(wrapper);
// Set the display list pointer of the new wrapper item to the display list
// of the wrapped item.
wrapper->mListPtr = wrappedItem->mListPtr;
return wrapper;
}
nsDisplayWrapList* nsDisplayListBuilder::MergeItems(
nsTArray<nsDisplayWrapList*>& 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* merged = nullptr;
nsDisplayWrapList* last = aItems.PopLastElement();
nsDisplayWrapList* merged = last->Clone(this);
MOZ_ASSERT(merged);
AddTemporaryItem(merged);
// 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)) {
MOZ_ASSERT(item);
if (!merged) {
// Create the temporary item.
merged = item->Clone(this);
MOZ_ASSERT(merged);
AddTemporaryItem(merged);
} else {
// Merge the item properties (frame/bounds/etc) with the previously
// created temporary item.
MOZ_ASSERT(merged->CanMerge(item));
merged->Merge(item);
}
// Create nsDisplayWrapList that points to the internal display list of the
// item we are merging. This nsDisplayWrapList is added to the display list
// of the temporary item.
merged->MergeDisplayListFromItem(this, item);
MOZ_ASSERT(merged->CanMerge(item));
merged->Merge(item);
merged->GetChildren()->AppendToTop(item->CreateShallowCopy(this));
}
merged->GetChildren()->AppendToTop(last->CreateShallowCopy(this));
return merged;
}
@ -4627,25 +4638,6 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
nsDisplayWrapList::~nsDisplayWrapList() { MOZ_COUNT_DTOR(nsDisplayWrapList); }
void nsDisplayWrapList::MergeDisplayListFromItem(
nsDisplayListBuilder* aBuilder, const nsDisplayWrapList* aItem) {
const nsDisplayWrapList* wrappedItem = aItem->AsDisplayWrapList();
MOZ_ASSERT(wrappedItem);
// Create a new nsDisplayWrapList using a copy-constructor. This is done
// to preserve the information about bounds.
nsDisplayWrapList* wrapper =
new (aBuilder) nsDisplayWrapper(aBuilder, *wrappedItem);
wrapper->SetType(nsDisplayWrapper::ItemType());
MOZ_ASSERT(wrapper);
// Set the display list pointer of the new wrapper item to the display list
// of the wrapped item.
wrapper->mListPtr = wrappedItem->mListPtr;
mListPtr->AppendToBottom(wrapper);
}
void nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder,
const nsRect& aRect, HitTestState* aState,
nsTArray<nsIFrame*>* aOutFrames) {

View File

@ -2996,8 +2996,8 @@ class nsPaintedDisplayItem : public nsDisplayItem {
* (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. AppendToBottom() is efficient too.
*/
* items and lists, with minimal codesize.
* */
class nsDisplayList {
public:
class Iterator {
@ -3144,41 +3144,6 @@ class nsDisplayList {
}
}
/**
* Append a new item to the bottom of the list. The item must be non-null
* and not already in a list.
*/
void AppendToBottom(nsDisplayItem* aItem) {
if (!aItem) {
return;
}
MOZ_ASSERT(!aItem->mAbove, "Already in a list!");
aItem->mAbove = mSentinel.mAbove;
mSentinel.mAbove = aItem;
if (mTop == &mSentinel) {
mTop = aItem;
}
mLength++;
}
template <typename T, typename F, typename... Args>
void AppendNewToBottom(nsDisplayListBuilder* aBuilder, F* aFrame,
Args&&... aArgs) {
AppendNewToBottomWithIndex<T>(aBuilder, aFrame, 0,
std::forward<Args>(aArgs)...);
}
template <typename T, typename F, typename... Args>
void AppendNewToBottomWithIndex(nsDisplayListBuilder* aBuilder, F* aFrame,
const uint16_t aIndex, Args&&... aArgs) {
nsDisplayItem* item = MakeDisplayItemWithIndex<T>(
aBuilder, aFrame, aIndex, std::forward<Args>(aArgs)...);
if (item) {
AppendToBottom(item);
}
}
/**
* Removes all items from aList and appends them to the top of this list
*/
@ -3193,24 +3158,6 @@ class nsDisplayList {
}
}
/**
* Removes all items from aList and prepends them to the bottom of this list
*/
void AppendToBottom(nsDisplayList* aList) {
if (aList->mSentinel.mAbove) {
aList->mTop->mAbove = mSentinel.mAbove;
mSentinel.mAbove = aList->mSentinel.mAbove;
if (mTop == &mSentinel) {
mTop = aList->mTop;
}
aList->mTop = &aList->mSentinel;
aList->mSentinel.mAbove = nullptr;
mLength += aList->mLength;
aList->mLength = 0;
}
}
/**
* Remove an item from the bottom of the list and return it.
*/
@ -4732,6 +4679,8 @@ class nsDisplayCompositorHitTestInfo final : public nsDisplayItem {
Maybe<int32_t> mOverrideZIndex;
};
class nsDisplayWrapper;
/**
* A class that lets you wrap a display list as a display item.
*
@ -4806,12 +4755,10 @@ class nsDisplayWrapList : public nsPaintedDisplayItem {
}
/**
* Creates a new nsDisplayWrapList that holds a pointer to the display list
* owned by the given nsDisplayItem. The new nsDisplayWrapList will be added
* to the bottom of this item's contents.
* Creates a new nsDisplayWrapper that holds a pointer to the display list
* owned by the given nsDisplayItem.
*/
void MergeDisplayListFromItem(nsDisplayListBuilder* aBuilder,
const nsDisplayWrapList* aItem);
nsDisplayWrapper* CreateShallowCopy(nsDisplayListBuilder* aBuilder);
/**
* Call this if the wrapped list is changed.