Bug 1883449 - [wpt-sync] Update web-platform-tests to bb67daef8e6a384ead5da4c991c12f8...
[gecko.git] / layout / painting / RetainedDisplayListBuilder.h
blobe9f5b56d1ba295210b6cb236958f6b7542705c4e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef RETAINEDDISPLAYLISTBUILDER_H_
8 #define RETAINEDDISPLAYLISTBUILDER_H_
10 #include "nsDisplayList.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/EnumSet.h"
14 class nsWindowSizes;
16 namespace mozilla {
18 class nsDisplayItem;
19 class nsDisplayList;
21 /**
22 * RetainedDisplayListData contains frame invalidation information.
23 * Currently this is implemented as a map of frame pointers to flags.
25 struct RetainedDisplayListData {
26 enum class FrameFlag : uint8_t { Modified, HasProps, HadWillChange };
27 using FrameFlags = mozilla::EnumSet<FrameFlag, uint8_t>;
29 RetainedDisplayListData();
31 /**
32 * Adds the frame to modified frames list.
34 void AddModifiedFrame(nsIFrame* aFrame);
36 /**
37 * Removes all the frames from this RetainedDisplayListData.
39 void Clear() {
40 mFrames.Clear();
41 mModifiedFrameCount = 0;
44 /**
45 * Returns a mutable reference to flags set for the given |aFrame|.
47 FrameFlags& Flags(nsIFrame* aFrame) { return mFrames.LookupOrInsert(aFrame); }
49 /**
50 * Returns flags set for the given |aFrame|, or FrameFlags::None if the frame
51 * is not in this RetainedDisplayListData.
53 FrameFlags GetFlags(nsIFrame* aFrame) const { return mFrames.Get(aFrame); }
55 bool IsModified(nsIFrame* aFrame) const {
56 return GetFlags(aFrame).contains(FrameFlag::Modified);
59 bool HasProps(nsIFrame* aFrame) const {
60 return GetFlags(aFrame).contains(FrameFlag::HasProps);
63 bool HadWillChange(nsIFrame* aFrame) const {
64 return GetFlags(aFrame).contains(FrameFlag::HadWillChange);
67 /**
68 * Returns an iterator to the underlying frame storage.
70 auto ConstIterator() { return mFrames.ConstIter(); }
72 /**
73 * Returns true if the modified frame limit has been reached.
75 bool AtModifiedFrameLimit() {
76 return mModifiedFrameCount >= mModifiedFrameLimit;
79 bool GetModifiedFrameCount() { return mModifiedFrameCount; }
81 /**
82 * Removes the given |aFrame| from this RetainedDisplayListData.
84 bool Remove(nsIFrame* aFrame) { return mFrames.Remove(aFrame); }
86 private:
87 nsTHashMap<nsPtrHashKey<nsIFrame>, FrameFlags> mFrames;
88 uint32_t mModifiedFrameCount = 0;
89 uint32_t mModifiedFrameLimit; // initialized to a pref value in constructor
92 enum class PartialUpdateResult { Failed, NoChange, Updated };
94 enum class PartialUpdateFailReason {
95 NA,
96 EmptyList,
97 RebuildLimit,
98 FrameType,
99 Disabled,
100 Content,
101 VisibleRect,
104 struct RetainedDisplayListMetrics {
105 RetainedDisplayListMetrics() { Reset(); }
107 void Reset() {
108 mNewItems = 0;
109 mRebuiltItems = 0;
110 mRemovedItems = 0;
111 mReusedItems = 0;
112 mTotalItems = 0;
113 mPartialBuildDuration = 0;
114 mFullBuildDuration = 0;
115 mPartialUpdateFailReason = PartialUpdateFailReason::NA;
116 mPartialUpdateResult = PartialUpdateResult::NoChange;
119 void StartBuild() { mStartTime = mozilla::TimeStamp::Now(); }
121 void EndFullBuild() { mFullBuildDuration = Elapsed(); }
123 void EndPartialBuild(PartialUpdateResult aResult) {
124 mPartialBuildDuration = Elapsed();
125 mPartialUpdateResult = aResult;
128 double Elapsed() {
129 return (mozilla::TimeStamp::Now() - mStartTime).ToMilliseconds();
132 const char* FailReasonString() const {
133 switch (mPartialUpdateFailReason) {
134 case PartialUpdateFailReason::NA:
135 return "N/A";
136 case PartialUpdateFailReason::EmptyList:
137 return "Empty list";
138 case PartialUpdateFailReason::RebuildLimit:
139 return "Rebuild limit";
140 case PartialUpdateFailReason::FrameType:
141 return "Frame type";
142 case PartialUpdateFailReason::Disabled:
143 return "Disabled";
144 case PartialUpdateFailReason::Content:
145 return "Content";
146 case PartialUpdateFailReason::VisibleRect:
147 return "VisibleRect";
148 default:
149 MOZ_ASSERT_UNREACHABLE("Enum value not handled!");
153 unsigned int mNewItems;
154 unsigned int mRebuiltItems;
155 unsigned int mRemovedItems;
156 unsigned int mReusedItems;
157 unsigned int mTotalItems;
159 mozilla::TimeStamp mStartTime;
160 double mPartialBuildDuration;
161 double mFullBuildDuration;
162 PartialUpdateFailReason mPartialUpdateFailReason;
163 PartialUpdateResult mPartialUpdateResult;
166 class RetainedDisplayListBuilder {
167 public:
168 RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
169 nsDisplayListBuilderMode aMode, bool aBuildCaret)
170 : mBuilder(aReferenceFrame, aMode, aBuildCaret, true), mList(&mBuilder) {}
171 ~RetainedDisplayListBuilder() { mList.DeleteAll(&mBuilder); }
173 nsDisplayListBuilder* Builder() { return &mBuilder; }
175 nsDisplayList* List() { return &mList; }
177 RetainedDisplayListMetrics* Metrics() { return &mMetrics; }
179 RetainedDisplayListData* Data() { return &mData; }
181 PartialUpdateResult AttemptPartialUpdate(nscolor aBackstop);
184 * Clears the modified state for frames in the retained display list data.
186 void ClearFramesWithProps();
188 void ClearRetainedData();
190 void ClearReuseableDisplayItems() { mBuilder.ClearReuseableDisplayItems(); }
192 void AddSizeOfIncludingThis(nsWindowSizes&) const;
194 NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
196 private:
197 void GetModifiedAndFramesWithProps(nsTArray<nsIFrame*>* aOutModifiedFrames,
198 nsTArray<nsIFrame*>* aOutFramesWithProps);
200 void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
203 * Invalidates the current and previous caret frame if they have changed.
205 void InvalidateCaretFramesIfNeeded();
208 * A simple early exit heuristic to avoid slow partial display list rebuilds.
209 * Returns true if a partial display list build should be attempted.
211 bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames);
214 * Recursively pre-processes the old display list tree before building the
215 * new partial display lists, and serializes the old list into an array,
216 * recording indices on items for fast lookup during merging. Builds an
217 * initial linear DAG for the list if we don't have an existing one. Finds
218 * items that have a different AGR from the specified one, and marks them to
219 * also be built so that we get relative ordering correct. Passes
220 * aKeepLinked=true internally for sub-lists that can't be changed to keep the
221 * original list structure linked for fast re-use.
223 bool PreProcessDisplayList(
224 RetainedDisplayList* aList, nsIFrame* aAGR, PartialUpdateResult& aUpdated,
225 nsIFrame* aAsyncAncestor, const ActiveScrolledRoot* aAsyncAncestorASR,
226 nsIFrame* aOuterFrame = nullptr, uint32_t aCallerKey = 0,
227 uint32_t aNestingDepth = 0, bool aKeepLinked = false);
230 * Merges items from aNewList into non-invalidated items from aOldList and
231 * stores the result in aOutList.
233 * aOuterItem is a pointer to an item that owns one of the lists, if
234 * available. If both lists are populated, then both outer items must not be
235 * invalidated, and identical, so either can be passed here.
237 * Returns true if changes were made, and the resulting display list (in
238 * aOutList) is different from aOldList.
240 bool MergeDisplayLists(
241 nsDisplayList* aNewList, RetainedDisplayList* aOldList,
242 RetainedDisplayList* aOutList,
243 mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
244 nsDisplayItem* aOuterItem = nullptr);
246 bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
247 nsRect* aOutDirty, nsIFrame** aOutModifiedAGR,
248 nsTArray<nsIFrame*>& aOutFramesWithProps);
250 bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
251 nsIFrame* aStopAtFrame,
252 nsTArray<nsIFrame*>& aOutFramesWithProps,
253 const bool aStopAtStackingContext, nsRect* aOutDirty,
254 nsIFrame** aOutModifiedAGR);
256 nsIFrame* RootReferenceFrame() { return mBuilder.RootReferenceFrame(); }
257 const nsIFrame* RootReferenceFrame() const {
258 return mBuilder.RootReferenceFrame();
261 nsRect RootOverflowRect() const;
264 * Tries to perform a simple partial display list build without display list
265 * merging. In this mode, only the top-level stacking context items and their
266 * contents are reused, when the frame subtree has not been modified.
268 bool TrySimpleUpdate(const nsTArray<nsIFrame*>& aModifiedFrames,
269 nsTArray<nsIFrame*>& aOutFramesWithProps);
271 friend class MergeState;
273 nsDisplayListBuilder mBuilder;
274 RetainedDisplayList mList;
275 WeakFrame mPreviousCaret;
276 RetainedDisplayListMetrics mMetrics;
277 RetainedDisplayListData mData;
280 namespace RDLUtils {
282 void AssertFrameSubtreeUnmodified(const nsIFrame* aFrame);
283 void AssertDisplayItemUnmodified(nsDisplayItem* aItem);
284 void AssertDisplayListUnmodified(nsDisplayList* aList);
286 } // namespace RDLUtils
287 } // namespace mozilla
289 #endif // RETAINEDDISPLAYLISTBUILDER_H_