зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1488599 - Part 1: Add RetainedDisplayListData that will store frame invalidation information r=mattwoodrow
Differential Revision: https://phabricator.services.mozilla.com/D5245 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d3a9739ed5
Коммит
f0b6dd8c41
|
@ -479,6 +479,14 @@ nsLayoutUtils::AreRetainedDisplayListsEnabled()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder(nsIFrame* aFrame)
|
||||
{
|
||||
const nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
|
||||
MOZ_ASSERT(displayRoot);
|
||||
return displayRoot->HasProperty(RetainedDisplayListBuilder::Cached());
|
||||
}
|
||||
|
||||
bool
|
||||
nsLayoutUtils::GPUImageScalingEnabled()
|
||||
{
|
||||
|
@ -1188,15 +1196,8 @@ nsLayoutUtils::InvalidateForDisplayPortChange(nsIContent* aContent,
|
|||
// rect properties on so we can find the frame later to remove the properties.
|
||||
frame->SchedulePaint();
|
||||
|
||||
if (!nsLayoutUtils::AreRetainedDisplayListsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(frame);
|
||||
RetainedDisplayListBuilder* retainedBuilder =
|
||||
displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
|
||||
|
||||
if (!retainedBuilder) {
|
||||
if (!nsLayoutUtils::AreRetainedDisplayListsEnabled() ||
|
||||
!nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder(frame)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1208,18 +1209,12 @@ nsLayoutUtils::InvalidateForDisplayPortChange(nsIContent* aContent,
|
|||
frame->SetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), rect);
|
||||
frame->SetHasOverrideDirtyRegion(true);
|
||||
|
||||
nsIFrame* rootFrame = frame->PresContext()->PresShell()->GetRootFrame();
|
||||
nsIFrame* rootFrame = frame->PresShell()->GetRootFrame();
|
||||
MOZ_ASSERT(rootFrame);
|
||||
|
||||
nsTArray<nsIFrame*>* frames =
|
||||
rootFrame->GetProperty(nsIFrame::OverriddenDirtyRectFrameList());
|
||||
|
||||
if (!frames) {
|
||||
frames = new nsTArray<nsIFrame*>();
|
||||
rootFrame->SetProperty(nsIFrame::OverriddenDirtyRectFrameList(), frames);
|
||||
}
|
||||
|
||||
frames->AppendElement(frame);
|
||||
RetainedDisplayListData* data =
|
||||
GetOrSetRetainedDisplayListData(rootFrame);
|
||||
data->Flags(frame) |= RetainedDisplayListData::FrameFlags::HasProps;
|
||||
}
|
||||
|
||||
if (aHadDisplayPort) {
|
||||
|
|
|
@ -2375,6 +2375,8 @@ public:
|
|||
*/
|
||||
static bool AreRetainedDisplayListsEnabled();
|
||||
|
||||
static bool DisplayRootHasRetainedDisplayListBuilder(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Find a suitable scale for a element (aFrame's content) over the course of any
|
||||
* animations and transitions of the CSS transform property on the
|
||||
|
|
|
@ -829,12 +829,14 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
|
|||
nsIFrame* rootFrame = shell->GetRootFrame();
|
||||
MOZ_ASSERT(rootFrame);
|
||||
if (this != rootFrame) {
|
||||
nsTArray<nsIFrame*>* modifiedFrames =
|
||||
rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
|
||||
if (modifiedFrames) {
|
||||
MOZ_ASSERT(!modifiedFrames->Contains(this),
|
||||
"A dtor added this frame to ModifiedFrameList");
|
||||
}
|
||||
const RetainedDisplayListData* data =
|
||||
GetRetainedDisplayListData(rootFrame);
|
||||
|
||||
const bool inModifiedList = data &&
|
||||
(data->GetFlags(this) & RetainedDisplayListData::FrameFlags::Modified);
|
||||
|
||||
MOZ_ASSERT(!inModifiedList,
|
||||
"A dtor added this frame to modified frames list!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -965,36 +967,30 @@ nsIFrame::RemoveDisplayItemDataForDeletion()
|
|||
delete items;
|
||||
}
|
||||
|
||||
if (IsFrameModified()) {
|
||||
nsIFrame* rootFrame = PresShell()->GetRootFrame();
|
||||
MOZ_ASSERT(rootFrame);
|
||||
|
||||
nsTArray<nsIFrame*>* modifiedFrames =
|
||||
rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
|
||||
MOZ_ASSERT(modifiedFrames);
|
||||
|
||||
for (auto& frame : *modifiedFrames) {
|
||||
if (frame == this) {
|
||||
frame = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nsLayoutUtils::AreRetainedDisplayListsEnabled()) {
|
||||
// Retained display lists are disabled, no need to update
|
||||
// RetainedDisplayListData.
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasOverrideDirtyRegion()) {
|
||||
nsIFrame* rootFrame = PresShell()->GetRootFrame();
|
||||
MOZ_ASSERT(rootFrame);
|
||||
const bool updateData =
|
||||
IsFrameModified() || HasOverrideDirtyRegion() || MayHaveWillChangeBudget();
|
||||
|
||||
nsTArray<nsIFrame*>* frames =
|
||||
rootFrame->GetProperty(nsIFrame::OverriddenDirtyRectFrameList());
|
||||
MOZ_ASSERT(frames);
|
||||
if (!updateData) {
|
||||
// No RetainedDisplayListData to update.
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& frame : *frames) {
|
||||
if (frame == this) {
|
||||
frame = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsIFrame* rootFrame = PresShell()->GetRootFrame();
|
||||
MOZ_ASSERT(rootFrame);
|
||||
|
||||
RetainedDisplayListData* data = GetOrSetRetainedDisplayListData(rootFrame);
|
||||
|
||||
if (IsFrameModified() || HasOverrideDirtyRegion()) {
|
||||
// Remove deleted frames from RetainedDisplayListData.
|
||||
DebugOnly<bool> removed = data->Remove(this);
|
||||
MOZ_ASSERT(removed,
|
||||
"Frame had flags set, but it was not found in DisplayListData!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1017,13 +1013,7 @@ nsIFrame::MarkNeedsDisplayItemRebuild()
|
|||
return;
|
||||
}
|
||||
|
||||
nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
|
||||
MOZ_ASSERT(displayRoot);
|
||||
|
||||
RetainedDisplayListBuilder* retainedBuilder =
|
||||
displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
|
||||
|
||||
if (!retainedBuilder) {
|
||||
if (!nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1034,36 +1024,13 @@ nsIFrame::MarkNeedsDisplayItemRebuild()
|
|||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsIFrame*>* modifiedFrames =
|
||||
rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
|
||||
|
||||
if (!modifiedFrames) {
|
||||
modifiedFrames = new nsTArray<nsIFrame*>();
|
||||
rootFrame->SetProperty(nsIFrame::ModifiedFrameList(), modifiedFrames);
|
||||
}
|
||||
|
||||
if (this == rootFrame) {
|
||||
// If this is the root frame, then marking us as needing a display
|
||||
// item rebuild implies the same for all our descendents. Clear them
|
||||
// all out to reduce the number of modified frames we keep around.
|
||||
for (nsIFrame* f : *modifiedFrames) {
|
||||
if (f) {
|
||||
f->SetFrameIsModified(false);
|
||||
}
|
||||
}
|
||||
modifiedFrames->Clear();
|
||||
} else if (modifiedFrames->Length() > gfxPrefs::LayoutRebuildFrameLimit()) {
|
||||
// If the list starts getting too big, then just mark the root frame
|
||||
// as needing a rebuild.
|
||||
rootFrame->MarkNeedsDisplayItemRebuild();
|
||||
return;
|
||||
}
|
||||
|
||||
modifiedFrames->AppendElement(this);
|
||||
|
||||
MOZ_ASSERT(PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0);
|
||||
RetainedDisplayListData* data = GetOrSetRetainedDisplayListData(rootFrame);
|
||||
data->Flags(this) |= RetainedDisplayListData::FrameFlags::Modified;
|
||||
SetFrameIsModified(true);
|
||||
|
||||
MOZ_ASSERT(
|
||||
PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0);
|
||||
|
||||
// Hopefully this is cheap, but we could use a frame state bit to note
|
||||
// the presence of dependencies to speed it up.
|
||||
DisplayItemArray* items = GetProperty(DisplayItems());
|
||||
|
|
|
@ -1251,8 +1251,6 @@ public:
|
|||
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(IBaselinePadProperty, nscoord)
|
||||
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(ModifiedFrameList, nsTArray<nsIFrame*>)
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(OverriddenDirtyRectFrameList, nsTArray<nsIFrame*>)
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayItems, DisplayItemArray)
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
|
||||
|
|
|
@ -41,6 +41,29 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
RetainedDisplayListData*
|
||||
GetRetainedDisplayListData(nsIFrame* aRootFrame)
|
||||
{
|
||||
RetainedDisplayListData* data =
|
||||
aRootFrame->GetProperty(RetainedDisplayListData::DisplayListData());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
RetainedDisplayListData*
|
||||
GetOrSetRetainedDisplayListData(nsIFrame* aRootFrame)
|
||||
{
|
||||
RetainedDisplayListData* data = GetRetainedDisplayListData(aRootFrame);
|
||||
|
||||
if (!data) {
|
||||
data = new RetainedDisplayListData();
|
||||
aRootFrame->SetProperty(RetainedDisplayListData::DisplayListData(), data);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
MarkFramesWithItemsAndImagesModified(nsDisplayList* aList)
|
||||
{
|
||||
|
@ -643,30 +666,26 @@ TakeAndAddModifiedAndFramesWithPropsFromRootFrame(
|
|||
{
|
||||
MOZ_ASSERT(aRootFrame);
|
||||
|
||||
nsTArray<nsIFrame*>* frames =
|
||||
aRootFrame->GetProperty(nsIFrame::ModifiedFrameList());
|
||||
RetainedDisplayListData* data = GetRetainedDisplayListData(aRootFrame);
|
||||
|
||||
if (frames) {
|
||||
for (nsIFrame* f : *frames) {
|
||||
if (f) {
|
||||
aModifiedFrames->AppendElement(f);
|
||||
}
|
||||
}
|
||||
|
||||
frames->Clear();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
frames = aRootFrame->GetProperty(nsIFrame::OverriddenDirtyRectFrameList());
|
||||
for (auto it = data->Iterator(); !it.Done(); it.Next()) {
|
||||
nsIFrame* frame = it.Key();
|
||||
const RetainedDisplayListData::FrameFlags& flags = it.Data();
|
||||
|
||||
if (frames) {
|
||||
for (nsIFrame* f : *frames) {
|
||||
if (f) {
|
||||
aFramesWithProps->AppendElement(f);
|
||||
}
|
||||
if (flags & RetainedDisplayListData::FrameFlags::Modified) {
|
||||
aModifiedFrames->AppendElement(frame);
|
||||
}
|
||||
|
||||
frames->Clear();
|
||||
if (flags & RetainedDisplayListData::FrameFlags::HasProps) {
|
||||
aFramesWithProps->AppendElement(frame);
|
||||
}
|
||||
}
|
||||
|
||||
data->Clear();
|
||||
}
|
||||
|
||||
struct CbData
|
||||
|
@ -1230,6 +1249,11 @@ ClearFrameProps(nsTArray<nsIFrame*>& aFrames)
|
|||
class AutoClearFramePropsArray
|
||||
{
|
||||
public:
|
||||
explicit AutoClearFramePropsArray(size_t aCapacity)
|
||||
: mFrames(aCapacity)
|
||||
{
|
||||
}
|
||||
|
||||
AutoClearFramePropsArray() = default;
|
||||
|
||||
~AutoClearFramePropsArray() { ClearFrameProps(mFrames); }
|
||||
|
@ -1268,7 +1292,7 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(
|
|||
// We set the override dirty regions during ComputeRebuildRegion or in
|
||||
// nsLayoutUtils::InvalidateForDisplayPortChange. The display port change also
|
||||
// marks the frame modified, so those regions are cleared here as well.
|
||||
AutoClearFramePropsArray modifiedFrames;
|
||||
AutoClearFramePropsArray modifiedFrames(64);
|
||||
AutoClearFramePropsArray framesWithProps;
|
||||
GetModifiedAndFramesWithProps(
|
||||
&mBuilder, &modifiedFrames.Frames(), &framesWithProps.Frames());
|
||||
|
|
|
@ -9,11 +9,78 @@
|
|||
|
||||
#include "nsDisplayList.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
namespace mozilla {
|
||||
class DisplayListChecker;
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
/**
|
||||
* RetainedDisplayListData contains frame invalidation information. It is stored
|
||||
* in root frames, and used by RetainedDisplayListBuilder.
|
||||
* Currently this is implemented as a map of frame pointers to flags.
|
||||
*/
|
||||
struct RetainedDisplayListData
|
||||
{
|
||||
NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListData, RetainedDisplayListData)
|
||||
|
||||
enum class FrameFlags : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
Modified = 1 << 0,
|
||||
HasProps = 1 << 1,
|
||||
HadWillChange = 1 << 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all the frames from this RetainedDisplayListData.
|
||||
*/
|
||||
void Clear() { mFrames.Clear(); }
|
||||
|
||||
/**
|
||||
* Returns a mutable reference to flags set for the given |aFrame|. If the
|
||||
* frame does not exist in this RetainedDisplayListData, it is added with
|
||||
* default constructible flags FrameFlags::None.
|
||||
*/
|
||||
FrameFlags& Flags(nsIFrame* aFrame) { return mFrames.GetOrInsert(aFrame); }
|
||||
|
||||
/**
|
||||
* Returns flags set for the given |aFrame|, or FrameFlags::None if the frame
|
||||
* is not in this RetainedDisplayListData.
|
||||
*/
|
||||
FrameFlags GetFlags(nsIFrame* aFrame) const { return mFrames.Get(aFrame); }
|
||||
|
||||
/**
|
||||
* Returns an iterator to the underlying frame storage.
|
||||
*/
|
||||
auto Iterator() { return mFrames.Iter(); }
|
||||
|
||||
/**
|
||||
* Removes the given |aFrame| from this RetainedDisplayListData.
|
||||
*/
|
||||
bool Remove(nsIFrame* aFrame) { return mFrames.Remove(aFrame); }
|
||||
|
||||
private:
|
||||
nsDataHashtable<nsPtrHashKey<nsIFrame>, FrameFlags> mFrames;
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(RetainedDisplayListData::FrameFlags)
|
||||
|
||||
/**
|
||||
* Returns RetainedDisplayListData property for the given |aRootFrame|, or
|
||||
* nullptr if the property is not set.
|
||||
*/
|
||||
RetainedDisplayListData*
|
||||
GetRetainedDisplayListData(nsIFrame* aRootFrame);
|
||||
|
||||
/**
|
||||
* Returns RetainedDisplayListData property for the given |aRootFrame|. Creates
|
||||
* and sets a new RetainedDisplayListData property if it is not already set.
|
||||
*/
|
||||
RetainedDisplayListData*
|
||||
GetOrSetRetainedDisplayListData(nsIFrame* aRootFrame);
|
||||
|
||||
struct RetainedDisplayListBuilder
|
||||
{
|
||||
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
|
|
|
@ -3359,7 +3359,7 @@ public:
|
|||
/**
|
||||
* Remove all items from the list and call their destructors.
|
||||
*/
|
||||
void DeleteAll(nsDisplayListBuilder* aBuilder);
|
||||
virtual void DeleteAll(nsDisplayListBuilder* aBuilder);
|
||||
|
||||
/**
|
||||
* @return the item at the top of the list, or null if the list is empty
|
||||
|
@ -3754,7 +3754,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
void DeleteAll(nsDisplayListBuilder* aBuilder)
|
||||
void DeleteAll(nsDisplayListBuilder* aBuilder) override
|
||||
{
|
||||
for (OldItemInfo& i : mOldItems) {
|
||||
if (i.mItem) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче