зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1697979 - Part 1: Reuse previously built stacking context display items without merging r=mstange
Differential Revision: https://phabricator.services.mozilla.com/D128413
This commit is contained in:
Родитель
cd7a04a37f
Коммит
07449db71e
|
@ -586,6 +586,12 @@ void DisplayPortUtils::InvalidateForDisplayPortChange(
|
|||
return;
|
||||
}
|
||||
|
||||
if (StaticPrefs::layout_display_list_retain_sc()) {
|
||||
// DisplayListBuildingDisplayPortRect property is not used when retain sc
|
||||
// mode is enabled.
|
||||
return;
|
||||
}
|
||||
|
||||
bool found;
|
||||
nsRect* rect = frame->GetProperty(
|
||||
nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), &found);
|
||||
|
|
|
@ -116,6 +116,24 @@ static void PrintDisplayItemTo(nsDisplayListBuilder* aBuilder,
|
|||
area.width, area.height);
|
||||
}
|
||||
|
||||
auto ReuseStateToString = [](nsDisplayItem::ReuseState aState) {
|
||||
switch (aState) {
|
||||
case nsDisplayItem::ReuseState::None:
|
||||
return "None";
|
||||
case nsDisplayItem::ReuseState::Reusable:
|
||||
return "Reusable";
|
||||
case nsDisplayItem::ReuseState::PreProcessed:
|
||||
return "PreProcessed";
|
||||
case nsDisplayItem::ReuseState::Reused:
|
||||
return "Reused";
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE();
|
||||
};
|
||||
|
||||
aStream << nsPrintfCString(" reuse-state(%s)",
|
||||
ReuseStateToString(aItem->GetReuseState()));
|
||||
|
||||
// Display item specific debug info
|
||||
aItem->WriteDebugInfo(aStream);
|
||||
|
||||
|
|
|
@ -3130,15 +3130,6 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
|
|||
|
||||
MOZ_ASSERT(builder && list && metrics);
|
||||
|
||||
// Retained builder exists, but display list retaining is disabled.
|
||||
if (!useRetainedBuilder && retainedBuilder) {
|
||||
// Clear the modified frames lists and frame properties.
|
||||
retainedBuilder->ClearFramesWithProps();
|
||||
|
||||
// Clear the retained display list.
|
||||
retainedBuilder->List()->DeleteAll(retainedBuilder->Builder());
|
||||
}
|
||||
|
||||
metrics->Reset();
|
||||
metrics->StartBuild();
|
||||
|
||||
|
@ -3320,15 +3311,11 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
|
|||
// If a pref is toggled that adds or removes display list items,
|
||||
// we need to rebuild the display list. The pref may be toggled
|
||||
// manually by the user, or during test setup.
|
||||
bool shouldAttemptPartialUpdate = useRetainedBuilder;
|
||||
if (builder->ShouldRebuildDisplayListDueToPrefChange()) {
|
||||
shouldAttemptPartialUpdate = false;
|
||||
}
|
||||
|
||||
// Attempt to do a partial build and merge into the existing list.
|
||||
// This calls BuildDisplayListForStacking context on a subset of the
|
||||
// viewport.
|
||||
if (shouldAttemptPartialUpdate) {
|
||||
if (useRetainedBuilder &&
|
||||
!builder->ShouldRebuildDisplayListDueToPrefChange()) {
|
||||
// Attempt to do a partial build and merge into the existing list.
|
||||
// This calls BuildDisplayListForStacking context on a subset of the
|
||||
// viewport.
|
||||
updateState = retainedBuilder->AttemptPartialUpdate(aBackstop);
|
||||
metrics->EndPartialBuild(updateState);
|
||||
} else {
|
||||
|
@ -3349,16 +3336,25 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
|
|||
}
|
||||
|
||||
if (doFullRebuild) {
|
||||
DL_LOGI("Starting full display list build, root frame: %p",
|
||||
builder->RootReferenceFrame());
|
||||
list->DeleteAll(builder);
|
||||
list->RestoreState();
|
||||
|
||||
if (useRetainedBuilder) {
|
||||
retainedBuilder->ClearFramesWithProps();
|
||||
mozilla::RDLUtils::AssertFrameSubtreeUnmodified(
|
||||
builder->RootReferenceFrame());
|
||||
MOZ_ASSERT(retainedBuilder->List()->IsEmpty());
|
||||
}
|
||||
|
||||
builder->ClearRetainedWindowRegions();
|
||||
builder->ClearWillChangeBudgets();
|
||||
|
||||
builder->EnterPresShell(aFrame);
|
||||
builder->SetDirtyRect(visibleRect);
|
||||
|
||||
DL_LOGI("Starting full display list build, root frame: %p",
|
||||
builder->RootReferenceFrame());
|
||||
|
||||
aFrame->BuildDisplayListForStackingContext(builder, list);
|
||||
AddExtraBackgroundItems(builder, list, aFrame, canvasArea,
|
||||
visibleRegion, aBackstop);
|
||||
|
|
|
@ -4488,23 +4488,25 @@ bool ScrollFrameHelper::DecideScrollableLayer(
|
|||
content, &displayPort,
|
||||
DisplayPortOptions().With(DisplayportRelativeTo::ScrollFrame));
|
||||
|
||||
auto OverrideDirtyRect = [&](const nsRect& aRect) {
|
||||
*aDirtyRect = aRect;
|
||||
if (aDirtyRectHasBeenOverriden) {
|
||||
*aDirtyRectHasBeenOverriden = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (usingDisplayPort) {
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
*aVisibleRect = displayPort;
|
||||
if (!aBuilder->IsPartialUpdate() || aBuilder->InInvalidSubtree() ||
|
||||
if (aBuilder->IsReusingStackingContextItems() ||
|
||||
!aBuilder->IsPartialUpdate() || aBuilder->InInvalidSubtree() ||
|
||||
mOuter->IsFrameModified()) {
|
||||
*aDirtyRect = displayPort;
|
||||
if (aDirtyRectHasBeenOverriden) {
|
||||
*aDirtyRectHasBeenOverriden = true;
|
||||
}
|
||||
OverrideDirtyRect(displayPort);
|
||||
} else if (mOuter->HasOverrideDirtyRegion()) {
|
||||
nsRect* rect = mOuter->GetProperty(
|
||||
nsDisplayListBuilder::DisplayListBuildingDisplayPortRect());
|
||||
if (rect) {
|
||||
*aDirtyRect = *rect;
|
||||
if (aDirtyRectHasBeenOverriden) {
|
||||
*aDirtyRectHasBeenOverriden = true;
|
||||
}
|
||||
OverrideDirtyRect(*rect);
|
||||
}
|
||||
}
|
||||
} else if (mIsRoot) {
|
||||
|
|
|
@ -1043,7 +1043,7 @@ void nsIFrame::RemoveDisplayItemDataForDeletion() {
|
|||
GetFrameName(name);
|
||||
}
|
||||
#endif
|
||||
DL_LOGD("Removing display item data for frame %p (%s)", this,
|
||||
DL_LOGV("Removing display item data for frame %p (%s)", this,
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
|
||||
// Destroying a WebRenderUserDataTable can cause destruction of other objects
|
||||
|
@ -1126,15 +1126,6 @@ void nsIFrame::MarkNeedsDisplayItemRebuild() {
|
|||
return;
|
||||
}
|
||||
|
||||
nsAutoString name;
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
if (DL_LOG_TEST(LogLevel::Debug)) {
|
||||
GetFrameName(name);
|
||||
}
|
||||
#endif
|
||||
DL_LOGD("RDL - Rebuilding display items for frame %p (%s)", this,
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
|
||||
nsIFrame* rootFrame = PresShell()->GetRootFrame();
|
||||
MOZ_ASSERT(rootFrame);
|
||||
|
||||
|
@ -1142,8 +1133,17 @@ void nsIFrame::MarkNeedsDisplayItemRebuild() {
|
|||
return;
|
||||
}
|
||||
|
||||
RetainedDisplayListData* data = GetOrSetRetainedDisplayListData(rootFrame);
|
||||
nsAutoString name;
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
if (DL_LOG_TEST(LogLevel::Debug)) {
|
||||
GetFrameName(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
DL_LOGV("RDL - Rebuilding display items for frame %p (%s)", this,
|
||||
NS_ConvertUTF16toUTF8(name).get());
|
||||
|
||||
RetainedDisplayListData* data = GetOrSetRetainedDisplayListData(rootFrame);
|
||||
if (data->ModifiedFramesCount() >
|
||||
StaticPrefs::layout_display_list_rebuild_frame_limit()) {
|
||||
// If the modified frames count is above the rebuild limit, mark the root
|
||||
|
@ -3089,6 +3089,41 @@ struct ContainerTracker {
|
|||
bool mCreatedContainer = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tries to reuse a top-level stacking context item from the previous paint.
|
||||
* Returns true if an item was reused, otherwise false.
|
||||
*/
|
||||
bool TryToReuseStackingContextItem(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aList, nsIFrame* aFrame) {
|
||||
if (!aBuilder->IsForPainting() || !aBuilder->IsPartialUpdate() ||
|
||||
aBuilder->InInvalidSubtree()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFrame->IsFrameModified() || aFrame->HasModifiedDescendants()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& items = aFrame->DisplayItems();
|
||||
auto* res = std::find_if(
|
||||
items.begin(), items.end(),
|
||||
[](nsDisplayItem* aItem) { return aItem->IsPreProcessed(); });
|
||||
|
||||
if (res == items.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
aList->AppendToTop(container);
|
||||
aBuilder->ReuseDisplayItem(container);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsIFrame::BuildDisplayListForStackingContext(
|
||||
nsDisplayListBuilder* aBuilder, nsDisplayList* aList,
|
||||
bool* aCreatedContainerItem) {
|
||||
|
@ -3103,7 +3138,18 @@ void nsIFrame::BuildDisplayListForStackingContext(
|
|||
});
|
||||
|
||||
AutoCheckBuilder check(aBuilder);
|
||||
if (HasAnyStateBits(NS_FRAME_TOO_DEEP_IN_FRAME_TREE)) return;
|
||||
|
||||
if (aBuilder->IsReusingStackingContextItems() &&
|
||||
TryToReuseStackingContextItem(aBuilder, aList, this)) {
|
||||
if (aCreatedContainerItem) {
|
||||
*aCreatedContainerItem = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasAnyStateBits(NS_FRAME_TOO_DEEP_IN_FRAME_TREE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsStyleDisplay* disp = StyleDisplay();
|
||||
const nsStyleEffects* effects = StyleEffects();
|
||||
|
@ -3258,7 +3304,8 @@ void nsIFrame::BuildDisplayListForStackingContext(
|
|||
//
|
||||
// These conditions should match |CanStoreDisplayListBuildingRect()| in
|
||||
// RetainedDisplayListBuilder.cpp
|
||||
if (aBuilder->IsPartialUpdate() && !aBuilder->InInvalidSubtree() &&
|
||||
if (!aBuilder->IsReusingStackingContextItems() &&
|
||||
aBuilder->IsPartialUpdate() && !aBuilder->InInvalidSubtree() &&
|
||||
!IsFrameModified() && IsFixedPosContainingBlock() &&
|
||||
!GetPrevContinuation() && !GetNextContinuation()) {
|
||||
dirtyRect = nsRect();
|
||||
|
@ -3439,6 +3486,7 @@ void nsIFrame::BuildDisplayListForStackingContext(
|
|||
MarkAbsoluteFramesForDisplayList(aBuilder);
|
||||
aBuilder->Check();
|
||||
BuildDisplayList(aBuilder, set);
|
||||
SetBuiltDisplayList(true);
|
||||
aBuilder->Check();
|
||||
aBuilder->DisplayCaret(this, set.Outlines());
|
||||
|
||||
|
@ -3804,15 +3852,39 @@ void nsIFrame::BuildDisplayListForStackingContext(
|
|||
CreateOwnLayerIfNeeded(aBuilder, &resultList,
|
||||
nsDisplayOwnLayer::OwnLayerForStackingContext,
|
||||
&createdOwnLayer);
|
||||
|
||||
if (createdOwnLayer) {
|
||||
ct.TrackContainer(resultList.GetTop());
|
||||
}
|
||||
|
||||
if (aBuilder->IsReusingStackingContextItems()) {
|
||||
if (resultList.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsDisplayItem* container = resultList.GetBottom();
|
||||
if (resultList.Count() > 1 || container->Frame() != this) {
|
||||
container = MakeDisplayItem<nsDisplayContainer>(
|
||||
aBuilder, this, containerItemASR, &resultList);
|
||||
} else {
|
||||
container = resultList.RemoveBottom();
|
||||
}
|
||||
|
||||
// Mark the outermost display item as reusable. These display items and
|
||||
// their chidren can be reused during the next paint if no ancestor or
|
||||
// descendant frames have been modified.
|
||||
if (!container->IsReusedItem()) {
|
||||
container->SetReusable();
|
||||
}
|
||||
aList->AppendToTop(container);
|
||||
ct.TrackContainer(container);
|
||||
} else {
|
||||
aList->AppendToTop(&resultList);
|
||||
}
|
||||
|
||||
if (aCreatedContainerItem) {
|
||||
*aCreatedContainerItem = ct.mCreatedContainer;
|
||||
}
|
||||
|
||||
aList->AppendToTop(&resultList);
|
||||
}
|
||||
|
||||
static nsDisplayItem* WrapInWrapList(nsDisplayListBuilder* aBuilder,
|
||||
|
@ -3973,6 +4045,7 @@ void nsIFrame::BuildDisplayListForSimpleChild(nsDisplayListBuilder* aBuilder,
|
|||
aBuilder->AdjustWindowDraggingRegion(aChild);
|
||||
aBuilder->Check();
|
||||
aChild->BuildDisplayList(aBuilder, aLists);
|
||||
aChild->SetBuiltDisplayList(true);
|
||||
aBuilder->Check();
|
||||
aBuilder->DisplayCaret(aChild, aLists.Outlines());
|
||||
#ifdef DEBUG
|
||||
|
@ -4181,8 +4254,6 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
awayFromCommonPath = true;
|
||||
}
|
||||
|
||||
child->SetBuiltDisplayList(true);
|
||||
|
||||
// Child is composited if it's transformed, partially transparent, or has
|
||||
// SVG effects or a blend mode..
|
||||
const nsStyleDisplay* disp = child->StyleDisplay();
|
||||
|
@ -4264,7 +4335,8 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
child->BuildDisplayListForStackingContext(aBuilder, &list,
|
||||
&builtContainerItem);
|
||||
wrapListASR = contASRTracker.GetContainerASR();
|
||||
if (aBuilder->GetCaretFrame() == child) {
|
||||
if (!aBuilder->IsReusingStackingContextItems() &&
|
||||
aBuilder->GetCaretFrame() == child) {
|
||||
builtContainerItem = false;
|
||||
}
|
||||
} else {
|
||||
|
@ -4279,6 +4351,7 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
|
||||
child->MarkAbsoluteFramesForDisplayList(aBuilder);
|
||||
child->SetBuiltDisplayList(true);
|
||||
|
||||
if (!awayFromCommonPath &&
|
||||
// Some SVG frames might change opacity without invalidating the frame,
|
||||
|
@ -4332,10 +4405,10 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
buildingForChild.RestoreBuildingInvisibleItemsValue();
|
||||
|
||||
if (isPositioned || isStackingContext) {
|
||||
// Genuine stacking contexts, and positioned pseudo-stacking-contexts,
|
||||
// go in this level.
|
||||
if (!list.IsEmpty()) {
|
||||
if (!list.IsEmpty()) {
|
||||
if (isPositioned || isStackingContext) {
|
||||
// Genuine stacking contexts, and positioned pseudo-stacking-contexts,
|
||||
// go in this level.
|
||||
nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR,
|
||||
builtContainerItem);
|
||||
if (isSVG) {
|
||||
|
@ -4343,14 +4416,12 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
|||
} else {
|
||||
aLists.PositionedDescendants()->AppendToTop(item);
|
||||
}
|
||||
}
|
||||
} else if (!isSVG && disp->IsFloating(child)) {
|
||||
if (!list.IsEmpty()) {
|
||||
} else if (!isSVG && disp->IsFloating(child)) {
|
||||
aLists.Floats()->AppendToTop(
|
||||
WrapInWrapList(aBuilder, child, &list, wrapListASR));
|
||||
} else {
|
||||
aLists.Content()->AppendToTop(&list);
|
||||
}
|
||||
} else {
|
||||
aLists.Content()->AppendToTop(&list);
|
||||
}
|
||||
// We delay placing the positioned descendants of positioned frames to here,
|
||||
// because in the absence of z-index this is the correct order for them.
|
||||
|
@ -7985,6 +8056,14 @@ void nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix,
|
|||
aTo += ToString(pseudoType).c_str();
|
||||
}
|
||||
aTo += "]";
|
||||
|
||||
if (IsFrameModified()) {
|
||||
aTo += nsPrintfCString(" modified");
|
||||
}
|
||||
|
||||
if (HasModifiedDescendants()) {
|
||||
aTo += nsPrintfCString(" has-modified-descendants");
|
||||
}
|
||||
}
|
||||
|
||||
void nsIFrame::List(FILE* out, const char* aPrefix, ListFlags aFlags) const {
|
||||
|
|
|
@ -599,6 +599,7 @@ class nsIFrame : public nsQueryFrame {
|
|||
mForceDescendIntoIfVisible(false),
|
||||
mBuiltDisplayList(false),
|
||||
mFrameIsModified(false),
|
||||
mHasModifiedDescendants(false),
|
||||
mHasOverrideDirtyRegion(false),
|
||||
mMayHaveWillChangeBudget(false),
|
||||
mIsPrimaryFrame(false),
|
||||
|
@ -4893,6 +4894,11 @@ class nsIFrame : public nsQueryFrame {
|
|||
mFrameIsModified = aFrameIsModified;
|
||||
}
|
||||
|
||||
bool HasModifiedDescendants() const { return mHasModifiedDescendants; }
|
||||
void SetHasModifiedDescendants(const bool aHasModifiedDescendants) {
|
||||
mHasModifiedDescendants = aHasModifiedDescendants;
|
||||
}
|
||||
|
||||
bool HasOverrideDirtyRegion() const { return mHasOverrideDirtyRegion; }
|
||||
void SetHasOverrideDirtyRegion(const bool aHasDirtyRegion) {
|
||||
mHasOverrideDirtyRegion = aHasDirtyRegion;
|
||||
|
@ -5128,8 +5134,22 @@ class nsIFrame : public nsQueryFrame {
|
|||
*/
|
||||
bool mBuiltDisplayList : 1;
|
||||
|
||||
/**
|
||||
* True if the frame has been marked modified by
|
||||
* |MarkNeedsDisplayItemRebuild()|, usually due to a style change or reflow.
|
||||
*/
|
||||
bool mFrameIsModified : 1;
|
||||
|
||||
/**
|
||||
* True if the frame has modified descendants. Set before display list
|
||||
* preprocessing and only used during partial display list builds.
|
||||
*/
|
||||
bool mHasModifiedDescendants : 1;
|
||||
|
||||
/**
|
||||
* Used by merging based retained display lists to restrict the dirty area
|
||||
* during partial display list builds.
|
||||
*/
|
||||
bool mHasOverrideDirtyRegion : 1;
|
||||
|
||||
/**
|
||||
|
|
|
@ -10293,8 +10293,9 @@ void nsTextFrame::ToCString(nsCString& aBuf) const {
|
|||
return;
|
||||
}
|
||||
|
||||
const uint32_t contentLength = AssertedCast<uint32_t>(GetContentLength());
|
||||
if (0 == contentLength) {
|
||||
const int32_t length = GetContentEnd() - mContentOffset;
|
||||
if (length <= 0) {
|
||||
// Negative lengths are possible during invalidation.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "RetainedDisplayListBuilder.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIFrameInlines.h"
|
||||
|
@ -112,6 +113,7 @@ static void MarkFramesWithItemsAndImagesModified(nsDisplayList* aList) {
|
|||
}
|
||||
|
||||
if (invalidate) {
|
||||
DL_LOGV("Invalidating item %p (%s)", i, i->Name());
|
||||
i->FrameForInvalidation()->MarkNeedsDisplayItemRebuild();
|
||||
if (i->GetDependentFrame()) {
|
||||
i->GetDependentFrame()->MarkNeedsDisplayItemRebuild();
|
||||
|
@ -355,8 +357,8 @@ bool RetainedDisplayListBuilder::PreProcessDisplayList(
|
|||
return true;
|
||||
}
|
||||
|
||||
void RetainedDisplayListBuilder::IncrementSubDocPresShellPaintCount(
|
||||
nsDisplayItem* aItem) {
|
||||
void IncrementPresShellPaintCount(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayItem* aItem) {
|
||||
MOZ_ASSERT(aItem->GetType() == DisplayItemType::TYPE_SUBDOCUMENT);
|
||||
|
||||
nsSubDocumentFrame* subDocFrame =
|
||||
|
@ -366,7 +368,12 @@ void RetainedDisplayListBuilder::IncrementSubDocPresShellPaintCount(
|
|||
PresShell* presShell = subDocFrame->GetSubdocumentPresShellForPainting(0);
|
||||
MOZ_ASSERT(presShell);
|
||||
|
||||
mBuilder.IncrementPresShellPaintCount(presShell);
|
||||
aBuilder->IncrementPresShellPaintCount(presShell);
|
||||
}
|
||||
|
||||
void RetainedDisplayListBuilder::IncrementSubDocPresShellPaintCount(
|
||||
nsDisplayItem* aItem) {
|
||||
IncrementPresShellPaintCount(&mBuilder, aItem);
|
||||
}
|
||||
|
||||
static Maybe<const ActiveScrolledRoot*> SelectContainerASR(
|
||||
|
@ -1401,6 +1408,7 @@ static void ClearFrameProps(nsTArray<nsIFrame*>& aFrames) {
|
|||
}
|
||||
|
||||
f->SetFrameIsModified(false);
|
||||
f->SetHasModifiedDescendants(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1424,6 +1432,232 @@ void RetainedDisplayListBuilder::ClearFramesWithProps() {
|
|||
&framesWithProps.Frames());
|
||||
}
|
||||
|
||||
namespace RDLUtils {
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG void AssertFrameSubtreeUnmodified(
|
||||
const nsIFrame* aFrame) {
|
||||
for (const auto& childList : aFrame->ChildLists()) {
|
||||
for (nsIFrame* child : childList.mList) {
|
||||
MOZ_ASSERT(!aFrame->IsFrameModified());
|
||||
MOZ_ASSERT(!aFrame->HasModifiedDescendants());
|
||||
AssertFrameSubtreeUnmodified(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG void AssertDisplayListUnmodified(nsDisplayList* aList) {
|
||||
for (nsDisplayItem* item : *aList) {
|
||||
AssertDisplayItemUnmodified(item);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG void AssertDisplayItemUnmodified(nsDisplayItem* aItem) {
|
||||
MOZ_ASSERT(!aItem->HasDeletedFrame());
|
||||
MOZ_ASSERT(!AnyContentAncestorModified(aItem->FrameForInvalidation()));
|
||||
|
||||
if (aItem->GetChildren()) {
|
||||
AssertDisplayListUnmodified(aItem->GetChildren());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RDLUtils
|
||||
|
||||
namespace RDL {
|
||||
|
||||
void MarkAncestorFrames(nsIFrame* aFrame,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps) {
|
||||
nsIFrame* frame = nsLayoutUtils::GetDisplayListParent(aFrame);
|
||||
while (frame && !frame->HasModifiedDescendants()) {
|
||||
aOutFramesWithProps.AppendElement(frame);
|
||||
frame->SetHasModifiedDescendants(true);
|
||||
frame = nsLayoutUtils::GetDisplayListParent(frame);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the modified frames array and updates the frame tree flags
|
||||
* so that container frames know whether they have modified descendant frames.
|
||||
* Frames that were marked modified are added to |aOutFramesWithProps|, so that
|
||||
* the modified status can be cleared after the display list build.
|
||||
*/
|
||||
void MarkAllAncestorFrames(const nsTArray<nsIFrame*>& aModifiedFrames,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps) {
|
||||
nsAutoString frameName;
|
||||
DL_LOGI("RDL - Modified frames: %zu", aModifiedFrames.Length());
|
||||
for (nsIFrame* frame : aModifiedFrames) {
|
||||
#ifdef DEBUG
|
||||
frame->GetFrameName(frameName);
|
||||
#endif
|
||||
DL_LOGV("RDL - Processing modified frame: %p (%s)", frame,
|
||||
NS_ConvertUTF16toUTF8(frameName).get());
|
||||
|
||||
MarkAncestorFrames(frame, aOutFramesWithProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given display item |aItem| as reuseable container, and updates the
|
||||
* bounds in case some child items were destroyed.
|
||||
*/
|
||||
MOZ_NEVER_INLINE_DEBUG void ReuseStackingContextItem(
|
||||
nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
|
||||
aItem->SetPreProcessed();
|
||||
|
||||
if (aItem->HasChildren()) {
|
||||
aItem->UpdateBounds(aBuilder);
|
||||
}
|
||||
|
||||
DL_LOGD("Retaining display item %p", aItem);
|
||||
}
|
||||
|
||||
bool IsSupportedFrameType(const nsIFrame* aFrame) {
|
||||
// The way table backgrounds are handled makes these frames incompatible with
|
||||
// this retained display list approach.
|
||||
if (aFrame->IsTableColFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFrame->IsTableColGroupFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFrame->IsTableRowFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFrame->IsTableRowGroupFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFrame->IsTableCellFrame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything else should work.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsReuseableStackingContextItem(nsDisplayItem* aItem) {
|
||||
if (!IsSupportedFrameType(aItem->Frame())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aItem->IsReusable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nsIFrame* frame = aItem->FrameForInvalidation();
|
||||
return !frame->HasModifiedDescendants() && !frame->GetPrevContinuation() &&
|
||||
!frame->GetNextContinuation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively visits every display item of the display list and destroys all
|
||||
* display items that depend on deleted or modified frames.
|
||||
* The stacking context display items for unmodified frame subtrees are kept
|
||||
* linked and collected in given |aOutItems| array.
|
||||
*/
|
||||
void CollectStackingContextItems(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aList,
|
||||
nsTArray<nsDisplayItem*>& aOutItems,
|
||||
nsIFrame* aOuterFrame, int aDepth = 0,
|
||||
bool aParentReused = false) {
|
||||
nsDisplayList out;
|
||||
|
||||
while (nsDisplayItem* item = aList->RemoveBottom()) {
|
||||
if (DL_LOG_TEST(LogLevel::Debug)) {
|
||||
DL_LOGD(
|
||||
"%*s Preprocessing item %p (%s) (frame: %p) "
|
||||
"(children: %d) (depth: %d) (parentReused: %d)",
|
||||
aDepth, "", item, item->Name(),
|
||||
item->HasDeletedFrame() ? nullptr : item->Frame(),
|
||||
item->GetChildren() ? item->GetChildren()->Count() : 0, aDepth,
|
||||
aParentReused);
|
||||
}
|
||||
|
||||
if (!item->CanBeReused() || item->HasDeletedFrame() ||
|
||||
AnyContentAncestorModified(item->FrameForInvalidation(), aOuterFrame)) {
|
||||
DL_LOGD("%*s Deleted modified or temporary item %p", aDepth, "", item);
|
||||
item->Destroy(aBuilder);
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!AnyContentAncestorModified(item->FrameForInvalidation()));
|
||||
MOZ_ASSERT(!item->IsPreProcessed());
|
||||
item->InvalidateCachedChildInfo(aBuilder);
|
||||
item->SetMergedPreProcessed(false, true);
|
||||
item->SetReused(true);
|
||||
|
||||
const bool isStackingContextItem = IsReuseableStackingContextItem(item);
|
||||
|
||||
if (item->GetChildren()) {
|
||||
CollectStackingContextItems(aBuilder, item->GetChildren(), aOutItems,
|
||||
item->Frame(), aDepth + 1,
|
||||
aParentReused || isStackingContextItem);
|
||||
}
|
||||
|
||||
if (aParentReused) {
|
||||
// Keep the contents of the current container item linked.
|
||||
RDLUtils::AssertDisplayItemUnmodified(item);
|
||||
out.AppendToTop(item);
|
||||
} else if (isStackingContextItem) {
|
||||
// |item| is a stacking context item that can be reused.
|
||||
aOutItems.AppendElement(item);
|
||||
ReuseStackingContextItem(aBuilder, item);
|
||||
} else {
|
||||
// |item| is inside a container item that will be destroyed later.
|
||||
DL_LOGD("%*s Deleted unused item %p", aDepth, "", item);
|
||||
item->Destroy(aBuilder);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->GetType() == DisplayItemType::TYPE_SUBDOCUMENT) {
|
||||
IncrementPresShellPaintCount(aBuilder, item);
|
||||
}
|
||||
}
|
||||
|
||||
aList->AppendToTop(&out);
|
||||
aList->RestoreState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the retained stacking context items that have not been reused and
|
||||
* clears the array.
|
||||
*/
|
||||
void ClearPreviousItems(nsDisplayListBuilder* aBuilder,
|
||||
nsTArray<nsDisplayItem*>& aItems) {
|
||||
const size_t total = aItems.Length();
|
||||
size_t reused = 0;
|
||||
for (auto* item : aItems) {
|
||||
if (item->IsReusedItem()) {
|
||||
reused++;
|
||||
item->SetReusable();
|
||||
} else {
|
||||
item->Destroy(aBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
DL_LOGI("RDL - Reused %zu of %zu SC display items", reused, total);
|
||||
aItems.Clear();
|
||||
}
|
||||
|
||||
} // namespace RDL
|
||||
|
||||
bool RetainedDisplayListBuilder::TrySimpleUpdate(
|
||||
const nsTArray<nsIFrame*>& aModifiedFrames,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps) {
|
||||
if (!mBuilder.IsReusingStackingContextItems()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPreviousItems.IsEmpty());
|
||||
RDL::MarkAllAncestorFrames(aModifiedFrames, aOutFramesWithProps);
|
||||
RDL::CollectStackingContextItems(&mBuilder, &mList, mPreviousItems,
|
||||
RootReferenceFrame());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
|
||||
nscolor aBackstop) {
|
||||
DL_LOGI("RDL - AttemptPartialUpdate, root frame: %p", RootReferenceFrame());
|
||||
|
@ -1437,32 +1671,43 @@ PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
|
|||
|
||||
InvalidateCaretFramesIfNeeded();
|
||||
|
||||
mBuilder.EnterPresShell(mBuilder.RootReferenceFrame());
|
||||
|
||||
// We set the override dirty regions during ComputeRebuildRegion or in
|
||||
// DisplayPortUtils::InvalidateForDisplayPortChange. The display port change
|
||||
// also marks the frame modified, so those regions are cleared here as well.
|
||||
AutoClearFramePropsArray modifiedFrames(64);
|
||||
AutoClearFramePropsArray framesWithProps;
|
||||
AutoClearFramePropsArray framesWithProps(64);
|
||||
GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames.Frames(),
|
||||
&framesWithProps.Frames());
|
||||
|
||||
// Do not allow partial builds if the |ShouldBuildPartial()| heuristic fails.
|
||||
bool shouldBuildPartial = ShouldBuildPartial(modifiedFrames.Frames());
|
||||
if (!ShouldBuildPartial(modifiedFrames.Frames())) {
|
||||
// Do not allow partial builds if the |ShouldBuildPartial()| heuristic
|
||||
// fails.
|
||||
mBuilder.SetPartialBuildFailed(true);
|
||||
return PartialUpdateResult::Failed;
|
||||
}
|
||||
|
||||
nsRect modifiedDirty;
|
||||
nsDisplayList modifiedDL;
|
||||
nsIFrame* modifiedAGR = nullptr;
|
||||
PartialUpdateResult result = PartialUpdateResult::NoChange;
|
||||
if (!shouldBuildPartial ||
|
||||
!ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
|
||||
&modifiedAGR, framesWithProps.Frames()) ||
|
||||
!PreProcessDisplayList(&mList, modifiedAGR, result,
|
||||
mBuilder.RootReferenceFrame(), nullptr)) {
|
||||
mBuilder.SetPartialBuildFailed(true);
|
||||
mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
|
||||
mList.DeleteAll(&mBuilder);
|
||||
return PartialUpdateResult::Failed;
|
||||
const bool simpleUpdate =
|
||||
TrySimpleUpdate(modifiedFrames.Frames(), framesWithProps.Frames());
|
||||
|
||||
mBuilder.EnterPresShell(RootReferenceFrame());
|
||||
|
||||
if (!simpleUpdate) {
|
||||
if (!ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
|
||||
&modifiedAGR, framesWithProps.Frames()) ||
|
||||
!PreProcessDisplayList(&mList, modifiedAGR, result,
|
||||
RootReferenceFrame(), nullptr)) {
|
||||
DL_LOGI("RDL - Partial update aborted");
|
||||
mBuilder.SetPartialBuildFailed(true);
|
||||
mBuilder.LeavePresShell(RootReferenceFrame(), nullptr);
|
||||
mList.DeleteAll(&mBuilder);
|
||||
return PartialUpdateResult::Failed;
|
||||
}
|
||||
} else {
|
||||
modifiedDirty = mBuilder.GetVisibleRect();
|
||||
}
|
||||
|
||||
// This is normally handled by EnterPresShell, but we skipped it so that we
|
||||
|
@ -1499,6 +1744,7 @@ PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
|
|||
if (mBuilder.PartialBuildFailed()) {
|
||||
DL_LOGI("RDL - Partial update failed!");
|
||||
mBuilder.LeavePresShell(RootReferenceFrame(), nullptr);
|
||||
RDL::ClearPreviousItems(&mBuilder, mPreviousItems);
|
||||
mList.DeleteAll(&mBuilder);
|
||||
modifiedDL.DeleteAll(&mBuilder);
|
||||
Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::Content;
|
||||
|
@ -1519,15 +1765,26 @@ PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
|
|||
// we call RestoreState on nsDisplayWrapList it resets the clip to the base
|
||||
// clip, and we need the UpdateBounds call (within MergeDisplayLists) to
|
||||
// move it to the correct inner clip.
|
||||
Maybe<const ActiveScrolledRoot*> dummy;
|
||||
if (MergeDisplayLists(&modifiedDL, &mList, &mList, dummy)) {
|
||||
if (!simpleUpdate) {
|
||||
Maybe<const ActiveScrolledRoot*> dummy;
|
||||
if (MergeDisplayLists(&modifiedDL, &mList, &mList, dummy)) {
|
||||
result = PartialUpdateResult::Updated;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mList.IsEmpty());
|
||||
mList = std::move(modifiedDL);
|
||||
RDL::ClearPreviousItems(&mBuilder, mPreviousItems);
|
||||
result = PartialUpdateResult::Updated;
|
||||
}
|
||||
|
||||
// printf_stderr("Painting --- Merged list:\n");
|
||||
// nsIFrame::PrintDisplayList(&mBuilder, mList);
|
||||
#if 0
|
||||
if (DL_LOG_TEST(LogLevel::Verbose)) {
|
||||
printf_stderr("Painting --- Display list:\n");
|
||||
nsIFrame::PrintDisplayList(&mBuilder, mList);
|
||||
}
|
||||
#endif
|
||||
|
||||
mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), List());
|
||||
mBuilder.LeavePresShell(RootReferenceFrame(), List());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ class nsWindowSizes;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
class nsDisplayItem;
|
||||
class nsDisplayList;
|
||||
|
||||
/**
|
||||
* RetainedDisplayListData contains frame invalidation information. It is stored
|
||||
* in root frames, and used by RetainedDisplayListBuilder.
|
||||
|
@ -254,15 +257,33 @@ struct RetainedDisplayListBuilder {
|
|||
nsIFrame** aOutModifiedAGR);
|
||||
|
||||
nsIFrame* RootReferenceFrame() { return mBuilder.RootReferenceFrame(); }
|
||||
|
||||
/**
|
||||
* Tries to perform a simple partial display list build without display list
|
||||
* merging. In this mode, only the top-level stacking context items and their
|
||||
* contents are reused, when the frame subtree has not been modified.
|
||||
*/
|
||||
bool TrySimpleUpdate(const nsTArray<nsIFrame*>& aModifiedFrames,
|
||||
nsTArray<nsIFrame*>& aOutFramesWithProps);
|
||||
|
||||
friend class MergeState;
|
||||
|
||||
nsDisplayListBuilder mBuilder;
|
||||
RetainedDisplayList mList;
|
||||
nsRect mPreviousVisibleRect;
|
||||
WeakFrame mPreviousCaret;
|
||||
RetainedDisplayListMetrics mMetrics;
|
||||
|
||||
// Stores reusable items collected during display list preprocessing.
|
||||
nsTArray<nsDisplayItem*> mPreviousItems;
|
||||
};
|
||||
|
||||
namespace RDLUtils {
|
||||
|
||||
void AssertFrameSubtreeUnmodified(const nsIFrame* aFrame);
|
||||
void AssertDisplayItemUnmodified(nsDisplayItem* aItem);
|
||||
void AssertDisplayListUnmodified(nsDisplayList* aList);
|
||||
|
||||
} // namespace RDLUtils
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // RETAINEDDISPLAYLISTBUILDER_H_
|
||||
|
|
|
@ -126,7 +126,7 @@ void AssertUniqueItem(nsDisplayItem* aItem) {
|
|||
for (nsDisplayItem* i : aItem->Frame()->DisplayItems()) {
|
||||
if (i != aItem && !i->HasDeletedFrame() && i->Frame() == aItem->Frame() &&
|
||||
i->GetPerFrameKey() == aItem->GetPerFrameKey()) {
|
||||
if (i->IsPreProcessedItem()) {
|
||||
if (i->IsPreProcessedItem() || i->IsPreProcessed()) {
|
||||
continue;
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "Duplicate display item!");
|
||||
|
@ -694,6 +694,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|||
static_cast<uint32_t>(DisplayItemType::TYPE_MAX) < (1 << TYPE_BITS),
|
||||
"Check TYPE_MAX should not overflow");
|
||||
mIsForContent = XRE_IsContentProcess();
|
||||
mIsReusingStackingContextItems =
|
||||
mRetainingDisplayList && StaticPrefs::layout_display_list_retain_sc();
|
||||
}
|
||||
|
||||
static PresShell* GetFocusedPresShell() {
|
||||
|
@ -2006,6 +2008,20 @@ void nsDisplayListBuilder::BuildCompositorHitTestInfoIfNeeded(
|
|||
}
|
||||
}
|
||||
|
||||
void nsDisplayListBuilder::ReuseDisplayItem(nsDisplayItem* aItem) {
|
||||
const auto* previous = mCurrentContainerASR;
|
||||
const auto* asr = aItem->GetActiveScrolledRoot();
|
||||
mCurrentContainerASR =
|
||||
ActiveScrolledRoot::PickAncestor(asr, mCurrentContainerASR);
|
||||
|
||||
if (previous != mCurrentContainerASR) {
|
||||
DL_LOGV("RDL - Changed mCurrentContainerASR from %p to %p", previous,
|
||||
mCurrentContainerASR);
|
||||
}
|
||||
|
||||
aItem->SetReusedItem();
|
||||
}
|
||||
|
||||
void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const {
|
||||
aDestination.BorderBackground()->AppendToTop(BorderBackground());
|
||||
aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
|
||||
|
|
|
@ -1691,6 +1691,20 @@ class nsDisplayListBuilder {
|
|||
*/
|
||||
nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Returns true if this is a retained builder and reuse stacking contexts
|
||||
* mode is enabled by pref.
|
||||
*/
|
||||
bool IsReusingStackingContextItems() const {
|
||||
return mIsReusingStackingContextItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given display item |aItem| as reused, and updates the necessary
|
||||
* display list builder state.
|
||||
*/
|
||||
void ReuseDisplayItem(nsDisplayItem* aItem);
|
||||
|
||||
private:
|
||||
bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
|
||||
const nsRect& aVisibleRect,
|
||||
|
@ -1885,6 +1899,7 @@ class nsDisplayListBuilder {
|
|||
gfx::CompositorHitTestInfo mCompositorHitTestInfo;
|
||||
|
||||
bool mIsForContent;
|
||||
bool mIsReusingStackingContextItems;
|
||||
};
|
||||
|
||||
class nsDisplayItem;
|
||||
|
@ -2756,6 +2771,44 @@ class nsDisplayItem : public nsDisplayItemLink {
|
|||
|
||||
virtual const HitTestInfo& GetHitTestInfo() { return HitTestInfo::Empty(); }
|
||||
|
||||
enum class ReuseState : uint8_t {
|
||||
None,
|
||||
// Set during display list building.
|
||||
Reusable,
|
||||
// Set during display list preprocessing.
|
||||
PreProcessed,
|
||||
// Set during partial display list build.
|
||||
Reused,
|
||||
};
|
||||
|
||||
void SetReusable() {
|
||||
MOZ_ASSERT(mReuseState == ReuseState::None ||
|
||||
mReuseState == ReuseState::Reused);
|
||||
mReuseState = ReuseState::Reusable;
|
||||
}
|
||||
|
||||
bool IsReusable() const { return mReuseState == ReuseState::Reusable; }
|
||||
|
||||
void SetPreProcessed() {
|
||||
MOZ_ASSERT(mReuseState == ReuseState::Reusable);
|
||||
mReuseState = ReuseState::PreProcessed;
|
||||
}
|
||||
|
||||
bool IsPreProcessed() const {
|
||||
return mReuseState == ReuseState::PreProcessed;
|
||||
}
|
||||
|
||||
void SetReusedItem() {
|
||||
MOZ_ASSERT(mReuseState == ReuseState::PreProcessed);
|
||||
mReuseState = ReuseState::Reused;
|
||||
}
|
||||
|
||||
bool IsReusedItem() const { return mReuseState == ReuseState::Reused; }
|
||||
|
||||
void ResetReuseState() { mReuseState = ReuseState::None; }
|
||||
|
||||
ReuseState GetReuseState() const { return mReuseState; }
|
||||
|
||||
nsIFrame* mFrame; // 8
|
||||
|
||||
private:
|
||||
|
@ -2784,7 +2837,7 @@ class nsDisplayItem : public nsDisplayItemLink {
|
|||
DisplayItemType mType = DisplayItemType::TYPE_ZERO; // 1
|
||||
uint8_t mExtraPageForPageNum = 0; // 1
|
||||
uint16_t mPerFrameIndex = 0; // 2
|
||||
// 2 free bytes here
|
||||
ReuseState mReuseState = ReuseState::None;
|
||||
OldListIndex mOldListIndex; // 4
|
||||
uintptr_t mOldList = 0; // 8
|
||||
|
||||
|
@ -3484,6 +3537,13 @@ class RetainedDisplayList : public nsDisplayList {
|
|||
return *this;
|
||||
}
|
||||
|
||||
RetainedDisplayList& operator=(nsDisplayList&& aOther) {
|
||||
MOZ_ASSERT(!Count(), "Can only move into an empty list!");
|
||||
MOZ_ASSERT(mOldItems.IsEmpty(), "Can only move into an empty list!");
|
||||
AppendToTop(&aOther);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DeleteAll(nsDisplayListBuilder* aBuilder) override {
|
||||
for (OldItemInfo& i : mOldItems) {
|
||||
if (i.mItem && i.mOwnsItem) {
|
||||
|
@ -3682,22 +3742,22 @@ class nsDisplayReflowCount : public nsPaintedDisplayItem {
|
|||
nscolor mColor;
|
||||
};
|
||||
|
||||
# define DO_GLOBAL_REFLOW_COUNT_DSP(_name) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
|
||||
PresShell()->IsPaintingFrameCounts()) { \
|
||||
aLists.Outlines()->AppendNewToTop<nsDisplayReflowCount>(aBuilder, this, \
|
||||
_name); \
|
||||
} \
|
||||
# define DO_GLOBAL_REFLOW_COUNT_DSP(_name) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
|
||||
PresShell()->IsPaintingFrameCounts()) { \
|
||||
aLists.Outlines()->AppendNewToTop<mozilla::nsDisplayReflowCount>( \
|
||||
aBuilder, this, _name); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
# define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
|
||||
PresShell()->IsPaintingFrameCounts()) { \
|
||||
aLists.Outlines()->AppendNewToTop<nsDisplayReflowCount>(aBuilder, this, \
|
||||
_name, _color); \
|
||||
} \
|
||||
# define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
|
||||
PresShell()->IsPaintingFrameCounts()) { \
|
||||
aLists.Outlines()->AppendNewToTop<mozilla::nsDisplayReflowCount>( \
|
||||
aBuilder, this, _name, _color); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
/*
|
||||
|
@ -4099,7 +4159,7 @@ class nsDisplayBackgroundImage : public nsPaintedDisplayItem {
|
|||
nsIFrame* GetDependentFrame() override { return mDependentFrame; }
|
||||
|
||||
void SetDependentFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
|
||||
if (!aBuilder->IsRetainingDisplayList()) {
|
||||
if (!aBuilder->IsRetainingDisplayList() || mDependentFrame == aFrame) {
|
||||
return;
|
||||
}
|
||||
mDependentFrame = aFrame;
|
||||
|
@ -4388,7 +4448,7 @@ class nsDisplayBackgroundColor : public nsPaintedDisplayItem {
|
|||
nsIFrame* GetDependentFrame() override { return mDependentFrame; }
|
||||
|
||||
void SetDependentFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
|
||||
if (!aBuilder->IsRetainingDisplayList()) {
|
||||
if (!aBuilder->IsRetainingDisplayList() || mDependentFrame == aFrame) {
|
||||
return;
|
||||
}
|
||||
mDependentFrame = aFrame;
|
||||
|
|
|
@ -340,8 +340,9 @@ void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey,
|
|||
bool aRebuildDisplayItems) {
|
||||
nsIFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
|
||||
if (GetTableFrame()->IsBorderCollapse()) {
|
||||
const bool rebuild = StaticPrefs::layout_display_list_retain_sc();
|
||||
GetParent()->InvalidateFrameWithRect(InkOverflowRect() + GetPosition(),
|
||||
aDisplayItemKey, false);
|
||||
aDisplayItemKey, rebuild);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,7 +355,7 @@ void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect,
|
|||
// we get an inactive layer created and this is computed
|
||||
// within FrameLayerBuilder
|
||||
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey,
|
||||
false);
|
||||
aRebuildDisplayItems);
|
||||
}
|
||||
|
||||
bool nsTableCellFrame::ShouldPaintBordersAndBackgrounds() const {
|
||||
|
|
|
@ -188,8 +188,9 @@ void nsTableColFrame::InvalidateFrame(uint32_t aDisplayItemKey,
|
|||
bool aRebuildDisplayItems) {
|
||||
nsIFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
|
||||
if (GetTableFrame()->IsBorderCollapse()) {
|
||||
const bool rebuild = StaticPrefs::layout_display_list_retain_sc();
|
||||
GetParent()->InvalidateFrameWithRect(InkOverflowRect() + GetPosition(),
|
||||
aDisplayItemKey, false);
|
||||
aDisplayItemKey, rebuild);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,5 +204,5 @@ void nsTableColFrame::InvalidateFrameWithRect(const nsRect& aRect,
|
|||
// we get an inactive layer created and this is computed
|
||||
// within FrameLayerBuilder
|
||||
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey,
|
||||
false);
|
||||
aRebuildDisplayItems);
|
||||
}
|
||||
|
|
|
@ -423,8 +423,9 @@ void nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey,
|
|||
bool aRebuildDisplayItems) {
|
||||
nsIFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
|
||||
if (GetTableFrame()->IsBorderCollapse()) {
|
||||
const bool rebuild = StaticPrefs::layout_display_list_retain_sc();
|
||||
GetParent()->InvalidateFrameWithRect(InkOverflowRect() + GetPosition(),
|
||||
aDisplayItemKey, false);
|
||||
aDisplayItemKey, rebuild);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,7 +438,7 @@ void nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect,
|
|||
// we get an inactive layer created and this is computed
|
||||
// within FrameLayerBuilder
|
||||
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey,
|
||||
false);
|
||||
aRebuildDisplayItems);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
|
|
|
@ -1388,8 +1388,9 @@ void nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey,
|
|||
bool aRebuildDisplayItems) {
|
||||
nsIFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
|
||||
if (GetTableFrame()->IsBorderCollapse()) {
|
||||
const bool rebuild = StaticPrefs::layout_display_list_retain_sc();
|
||||
GetParent()->InvalidateFrameWithRect(InkOverflowRect() + GetPosition(),
|
||||
aDisplayItemKey, false);
|
||||
aDisplayItemKey, rebuild);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1402,7 +1403,7 @@ void nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect,
|
|||
// we get an inactive layer created and this is computed
|
||||
// within FrameLayerBuilder
|
||||
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey,
|
||||
false);
|
||||
aRebuildDisplayItems);
|
||||
}
|
||||
|
||||
/* ----- global methods ----- */
|
||||
|
|
|
@ -1933,8 +1933,9 @@ void nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey,
|
|||
bool aRebuildDisplayItems) {
|
||||
nsIFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
|
||||
if (GetTableFrame()->IsBorderCollapse()) {
|
||||
const bool rebuild = StaticPrefs::layout_display_list_retain_sc();
|
||||
GetParent()->InvalidateFrameWithRect(InkOverflowRect() + GetPosition(),
|
||||
aDisplayItemKey, false);
|
||||
aDisplayItemKey, rebuild);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1947,5 +1948,5 @@ void nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect,
|
|||
// we get an inactive layer created and this is computed
|
||||
// within FrameLayerBuilder
|
||||
GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey,
|
||||
false);
|
||||
aRebuildDisplayItems);
|
||||
}
|
||||
|
|
|
@ -7749,6 +7749,11 @@
|
|||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: layout.display-list.retain.sc
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# Set the maximum number of modified frames allowed before doing a full
|
||||
# display list rebuild.
|
||||
- name: layout.display-list.rebuild-frame-limit
|
||||
|
|
Загрузка…
Ссылка в новой задаче