зеркало из https://github.com/mozilla/gecko-dev.git
266 строки
8.6 KiB
C++
266 строки
8.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef RETAINEDDISPLAYLISTBUILDER_H_
|
|
#define RETAINEDDISPLAYLISTBUILDER_H_
|
|
|
|
#include "nsDisplayList.h"
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/TypedEnumBits.h"
|
|
|
|
class nsWindowSizes;
|
|
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
|
|
};
|
|
|
|
RetainedDisplayListData() : mModifiedFramesCount(0) {}
|
|
|
|
/**
|
|
* Adds the frame to modified frames list.
|
|
*/
|
|
void AddModifiedFrame(nsIFrame* aFrame);
|
|
|
|
/**
|
|
* Removes all the frames from this RetainedDisplayListData.
|
|
*/
|
|
void Clear() {
|
|
mFrames.Clear();
|
|
mModifiedFramesCount = 0;
|
|
}
|
|
|
|
/**
|
|
* 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(); }
|
|
|
|
/**
|
|
* Returns the count of modified frames in this RetainedDisplayListData.
|
|
*/
|
|
uint32_t ModifiedFramesCount() const { return mModifiedFramesCount; }
|
|
|
|
/**
|
|
* Removes the given |aFrame| from this RetainedDisplayListData.
|
|
*/
|
|
bool Remove(nsIFrame* aFrame) { return mFrames.Remove(aFrame); }
|
|
|
|
private:
|
|
nsDataHashtable<nsPtrHashKey<nsIFrame>, FrameFlags> mFrames;
|
|
uint32_t mModifiedFramesCount;
|
|
};
|
|
|
|
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);
|
|
|
|
enum class PartialUpdateResult { Failed, NoChange, Updated };
|
|
|
|
enum class PartialUpdateFailReason {
|
|
NA,
|
|
EmptyList,
|
|
RebuildLimit,
|
|
FrameType,
|
|
Disabled,
|
|
Content,
|
|
VisibleRect,
|
|
};
|
|
|
|
struct RetainedDisplayListMetrics {
|
|
RetainedDisplayListMetrics() { Reset(); }
|
|
|
|
void Reset() {
|
|
mNewItems = 0;
|
|
mRebuiltItems = 0;
|
|
mRemovedItems = 0;
|
|
mReusedItems = 0;
|
|
mTotalItems = 0;
|
|
mPartialBuildDuration = 0;
|
|
mFullBuildDuration = 0;
|
|
mPartialUpdateFailReason = PartialUpdateFailReason::NA;
|
|
mPartialUpdateResult = PartialUpdateResult::NoChange;
|
|
}
|
|
|
|
void StartBuild() { mStartTime = mozilla::TimeStamp::Now(); }
|
|
|
|
void EndFullBuild() { mFullBuildDuration = Elapsed(); }
|
|
|
|
void EndPartialBuild(PartialUpdateResult aResult) {
|
|
mPartialBuildDuration = Elapsed();
|
|
mPartialUpdateResult = aResult;
|
|
}
|
|
|
|
double Elapsed() {
|
|
return (mozilla::TimeStamp::Now() - mStartTime).ToMilliseconds();
|
|
}
|
|
|
|
const char* FailReasonString() const {
|
|
switch (mPartialUpdateFailReason) {
|
|
case PartialUpdateFailReason::NA:
|
|
return "N/A";
|
|
case PartialUpdateFailReason::EmptyList:
|
|
return "Empty list";
|
|
case PartialUpdateFailReason::RebuildLimit:
|
|
return "Rebuild limit";
|
|
case PartialUpdateFailReason::FrameType:
|
|
return "Frame type";
|
|
case PartialUpdateFailReason::Disabled:
|
|
return "Disabled";
|
|
case PartialUpdateFailReason::Content:
|
|
return "Content";
|
|
case PartialUpdateFailReason::VisibleRect:
|
|
return "VisibleRect";
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("Enum value not handled!");
|
|
}
|
|
}
|
|
|
|
unsigned int mNewItems;
|
|
unsigned int mRebuiltItems;
|
|
unsigned int mRemovedItems;
|
|
unsigned int mReusedItems;
|
|
unsigned int mTotalItems;
|
|
|
|
mozilla::TimeStamp mStartTime;
|
|
double mPartialBuildDuration;
|
|
double mFullBuildDuration;
|
|
PartialUpdateFailReason mPartialUpdateFailReason;
|
|
PartialUpdateResult mPartialUpdateResult;
|
|
};
|
|
|
|
struct RetainedDisplayListBuilder {
|
|
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|
nsDisplayListBuilderMode aMode, bool aBuildCaret)
|
|
: mBuilder(aReferenceFrame, aMode, aBuildCaret, true) {}
|
|
~RetainedDisplayListBuilder() { mList.DeleteAll(&mBuilder); }
|
|
|
|
nsDisplayListBuilder* Builder() { return &mBuilder; }
|
|
|
|
nsDisplayList* List() { return &mList; }
|
|
|
|
RetainedDisplayListMetrics* Metrics() { return &mMetrics; }
|
|
|
|
PartialUpdateResult AttemptPartialUpdate(
|
|
nscolor aBackstop, mozilla::DisplayListChecker* aChecker);
|
|
|
|
/**
|
|
* Iterates through the display list builder reference frame document and
|
|
* subdocuments, and clears the modified frame lists from the root frames.
|
|
* Also clears the frame properties set by RetainedDisplayListBuilder for all
|
|
* the frames in the modified frame lists.
|
|
*/
|
|
void ClearFramesWithProps();
|
|
void AddSizeOfIncludingThis(nsWindowSizes&) const;
|
|
|
|
NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
|
|
|
|
private:
|
|
void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
|
|
|
|
/**
|
|
* Invalidates the current and previous caret frame if they have changed.
|
|
*/
|
|
void InvalidateCaretFramesIfNeeded();
|
|
|
|
/**
|
|
* A simple early exit heuristic to avoid slow partial display list rebuilds.
|
|
* Returns true if a partial display list build should be attempted.
|
|
*/
|
|
bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames);
|
|
|
|
/**
|
|
* Recursively pre-processes the old display list tree before building the
|
|
* new partial display lists, and serializes the old list into an array,
|
|
* recording indices on items for fast lookup during merging. Builds an
|
|
* initial linear DAG for the list if we don't have an existing one. Finds
|
|
* items that have a different AGR from the specified one, and marks them to
|
|
* also be built so that we get relative ordering correct. Passes
|
|
* aKeepLinked=true internally for sub-lists that can't be changed to keep the
|
|
* original list structure linked for fast re-use.
|
|
*/
|
|
bool PreProcessDisplayList(RetainedDisplayList* aList,
|
|
AnimatedGeometryRoot* aAGR,
|
|
PartialUpdateResult& aUpdated,
|
|
nsIFrame* aOuterFrame = nullptr,
|
|
uint32_t aCallerKey = 0,
|
|
uint32_t aNestingDepth = 0,
|
|
bool aKeepLinked = false);
|
|
|
|
/**
|
|
* Merges items from aNewList into non-invalidated items from aOldList and
|
|
* stores the result in aOutList.
|
|
*
|
|
* aOuterItem is a pointer to an item that owns one of the lists, if
|
|
* available. If both lists are populated, then both outer items must not be
|
|
* invalidated, and identical, so either can be passed here.
|
|
*
|
|
* Returns true if changes were made, and the resulting display list (in
|
|
* aOutList) is different from aOldList.
|
|
*/
|
|
bool MergeDisplayLists(
|
|
nsDisplayList* aNewList, RetainedDisplayList* aOldList,
|
|
RetainedDisplayList* aOutList,
|
|
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
|
|
nsDisplayItem* aOuterItem = nullptr);
|
|
|
|
bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
|
|
nsRect* aOutDirty,
|
|
AnimatedGeometryRoot** aOutModifiedAGR,
|
|
nsTArray<nsIFrame*>& aOutFramesWithProps);
|
|
|
|
bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
|
|
nsIFrame* aStopAtFrame,
|
|
nsTArray<nsIFrame*>& aOutFramesWithProps,
|
|
const bool aStopAtStackingContext, nsRect* aOutDirty,
|
|
AnimatedGeometryRoot** aOutModifiedAGR);
|
|
|
|
friend class MergeState;
|
|
|
|
nsDisplayListBuilder mBuilder;
|
|
RetainedDisplayList mList;
|
|
nsRect mPreviousVisibleRect;
|
|
WeakFrame mPreviousCaret;
|
|
RetainedDisplayListMetrics mMetrics;
|
|
};
|
|
|
|
#endif // RETAINEDDISPLAYLISTBUILDER_H_
|