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"
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();
32 * Adds the frame to modified frames list.
34 void AddModifiedFrame(nsIFrame
* aFrame
);
37 * Removes all the frames from this RetainedDisplayListData.
41 mModifiedFrameCount
= 0;
45 * Returns a mutable reference to flags set for the given |aFrame|.
47 FrameFlags
& Flags(nsIFrame
* aFrame
) { return mFrames
.LookupOrInsert(aFrame
); }
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
);
68 * Returns an iterator to the underlying frame storage.
70 auto ConstIterator() { return mFrames
.ConstIter(); }
73 * Returns true if the modified frame limit has been reached.
75 bool AtModifiedFrameLimit() {
76 return mModifiedFrameCount
>= mModifiedFrameLimit
;
79 bool GetModifiedFrameCount() { return mModifiedFrameCount
; }
82 * Removes the given |aFrame| from this RetainedDisplayListData.
84 bool Remove(nsIFrame
* aFrame
) { return mFrames
.Remove(aFrame
); }
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
{
104 struct RetainedDisplayListMetrics
{
105 RetainedDisplayListMetrics() { Reset(); }
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
;
129 return (mozilla::TimeStamp::Now() - mStartTime
).ToMilliseconds();
132 const char* FailReasonString() const {
133 switch (mPartialUpdateFailReason
) {
134 case PartialUpdateFailReason::NA
:
136 case PartialUpdateFailReason::EmptyList
:
138 case PartialUpdateFailReason::RebuildLimit
:
139 return "Rebuild limit";
140 case PartialUpdateFailReason::FrameType
:
142 case PartialUpdateFailReason::Disabled
:
144 case PartialUpdateFailReason::Content
:
146 case PartialUpdateFailReason::VisibleRect
:
147 return "VisibleRect";
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
{
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
)
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
;
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_