gecko-dev/layout/painting/RetainedDisplayListBuilder.h
Matt Woodrow 450f1a6f89 Bug 1544948 - Skip merging display lists that we're sure can't have changed. r=miko
ComputeRebuildRegion sets ForceDescendIntoIfVisible on all modified frames and their ancestors,
so we can use this to detect if a display list might have modified children by looking for this
flag on the container item.

We still need to run PreProcessDisplayList on the list, so that we can remove items that belong
to a deleted frame, and build the old items array (including placeholders for the deleted items)
so that it matches our DAG.

If we wanted to skip serialization to the old items array, then we'd need to remove the deleted
item entries from the DAG too, including connecting predecessors of the deleted entry to entries
that have that deleted entry as their predecessor. That's hard to do in-place, so we leave
the empty entries in the old items list to act as placeholders until we next merge this list
properly.

Differential Revision: https://phabricator.services.mozilla.com/D27822

--HG--
extra : moz-landing-system : lando
2019-04-29 03:14:49 +00:00

175 lines
6.2 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"
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);
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; }
enum class PartialUpdateResult { Failed, NoChange, Updated };
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();
NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
private:
/**
* 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,
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);
void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
friend class MergeState;
nsDisplayListBuilder mBuilder;
RetainedDisplayList mList;
WeakFrame mPreviousCaret;
};
#endif // RETAINEDDISPLAYLISTBUILDER_H_