tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RetainedDisplayListBuilder.h (9040B)


      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/. */
      6 
      7 #ifndef RETAINEDDISPLAYLISTBUILDER_H_
      8 #define RETAINEDDISPLAYLISTBUILDER_H_
      9 
     10 #include "mozilla/EnumSet.h"
     11 #include "mozilla/Maybe.h"
     12 #include "nsDisplayList.h"
     13 
     14 class nsWindowSizes;
     15 
     16 namespace mozilla {
     17 
     18 class nsDisplayItem;
     19 class nsDisplayList;
     20 
     21 /**
     22 * RetainedDisplayListData contains frame invalidation information.
     23 * Currently this is implemented as a map of frame pointers to flags.
     24 */
     25 struct RetainedDisplayListData {
     26  enum class FrameFlag : uint8_t { Modified, HasProps, HadWillChange };
     27  using FrameFlags = mozilla::EnumSet<FrameFlag, uint8_t>;
     28 
     29  RetainedDisplayListData();
     30 
     31  /**
     32   * Adds the frame to modified frames list.
     33   */
     34  void AddModifiedFrame(nsIFrame* aFrame);
     35 
     36  /**
     37   * Removes all the frames from this RetainedDisplayListData.
     38   */
     39  void Clear() {
     40    mFrames.Clear();
     41    mModifiedFrameCount = 0;
     42  }
     43 
     44  /**
     45   * Returns a mutable reference to flags set for the given |aFrame|.
     46   */
     47  FrameFlags& Flags(nsIFrame* aFrame) { return mFrames.LookupOrInsert(aFrame); }
     48 
     49  /**
     50   * Returns flags set for the given |aFrame|, or FrameFlags::None if the frame
     51   * is not in this RetainedDisplayListData.
     52   */
     53  FrameFlags GetFlags(nsIFrame* aFrame) const { return mFrames.Get(aFrame); }
     54 
     55  bool IsModified(nsIFrame* aFrame) const {
     56    return GetFlags(aFrame).contains(FrameFlag::Modified);
     57  }
     58 
     59  bool HasProps(nsIFrame* aFrame) const {
     60    return GetFlags(aFrame).contains(FrameFlag::HasProps);
     61  }
     62 
     63  /**
     64   * Returns an iterator to the underlying frame storage.
     65   */
     66  auto ConstIterator() { return mFrames.ConstIter(); }
     67 
     68  /**
     69   * Returns true if the modified frame limit has been reached.
     70   */
     71  bool AtModifiedFrameLimit() {
     72    return mModifiedFrameCount >= mModifiedFrameLimit;
     73  }
     74 
     75  bool GetModifiedFrameCount() { return mModifiedFrameCount; }
     76 
     77  /**
     78   * Removes the given |aFrame| from this RetainedDisplayListData.
     79   */
     80  bool Remove(nsIFrame* aFrame) { return mFrames.Remove(aFrame); }
     81 
     82 private:
     83  nsTHashMap<nsPtrHashKey<nsIFrame>, FrameFlags> mFrames;
     84  uint32_t mModifiedFrameCount = 0;
     85  uint32_t mModifiedFrameLimit;  // initialized to a pref value in constructor
     86 };
     87 
     88 enum class PartialUpdateResult { Failed, NoChange, Updated };
     89 
     90 enum class PartialUpdateFailReason {
     91  NA,
     92  EmptyList,
     93  RebuildLimit,
     94  FrameType,
     95  Disabled,
     96  Content,
     97  VisibleRect,
     98 };
     99 
    100 struct RetainedDisplayListMetrics {
    101  RetainedDisplayListMetrics() { Reset(); }
    102 
    103  void Reset() {
    104    mNewItems = 0;
    105    mRebuiltItems = 0;
    106    mRemovedItems = 0;
    107    mReusedItems = 0;
    108    mTotalItems = 0;
    109    mPartialBuildDuration = 0;
    110    mFullBuildDuration = 0;
    111    mPartialUpdateFailReason = PartialUpdateFailReason::NA;
    112    mPartialUpdateResult = PartialUpdateResult::NoChange;
    113  }
    114 
    115  void StartBuild() { mStartTime = mozilla::TimeStamp::Now(); }
    116 
    117  void EndFullBuild() { mFullBuildDuration = Elapsed(); }
    118 
    119  void EndPartialBuild(PartialUpdateResult aResult) {
    120    mPartialBuildDuration = Elapsed();
    121    mPartialUpdateResult = aResult;
    122  }
    123 
    124  double Elapsed() {
    125    return (mozilla::TimeStamp::Now() - mStartTime).ToMilliseconds();
    126  }
    127 
    128  const char* FailReasonString() const {
    129    switch (mPartialUpdateFailReason) {
    130      case PartialUpdateFailReason::NA:
    131        return "N/A";
    132      case PartialUpdateFailReason::EmptyList:
    133        return "Empty list";
    134      case PartialUpdateFailReason::RebuildLimit:
    135        return "Rebuild limit";
    136      case PartialUpdateFailReason::FrameType:
    137        return "Frame type";
    138      case PartialUpdateFailReason::Disabled:
    139        return "Disabled";
    140      case PartialUpdateFailReason::Content:
    141        return "Content";
    142      case PartialUpdateFailReason::VisibleRect:
    143        return "VisibleRect";
    144      default:
    145        MOZ_ASSERT_UNREACHABLE("Enum value not handled!");
    146    }
    147  }
    148 
    149  unsigned int mNewItems;
    150  unsigned int mRebuiltItems;
    151  unsigned int mRemovedItems;
    152  unsigned int mReusedItems;
    153  unsigned int mTotalItems;
    154 
    155  mozilla::TimeStamp mStartTime;
    156  double mPartialBuildDuration;
    157  double mFullBuildDuration;
    158  PartialUpdateFailReason mPartialUpdateFailReason;
    159  PartialUpdateResult mPartialUpdateResult;
    160 };
    161 
    162 class RetainedDisplayListBuilder {
    163 public:
    164  RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
    165                             nsDisplayListBuilderMode aMode, bool aBuildCaret)
    166      : mBuilder(aReferenceFrame, aMode, aBuildCaret, true), mList(&mBuilder) {}
    167  ~RetainedDisplayListBuilder() {
    168    mBuilder.SetIsDestroying();
    169    mList.DeleteAll(&mBuilder);
    170  }
    171 
    172  nsDisplayListBuilder* Builder() { return &mBuilder; }
    173 
    174  nsDisplayList* List() { return &mList; }
    175 
    176  RetainedDisplayListMetrics* Metrics() { return &mMetrics; }
    177 
    178  RetainedDisplayListData* Data() { return &mData; }
    179 
    180  PartialUpdateResult AttemptPartialUpdate(nscolor aBackstop);
    181 
    182  /**
    183   * Clears the modified state for frames in the retained display list data.
    184   */
    185  void ClearFramesWithProps();
    186 
    187  void ClearRetainedData();
    188 
    189  void ClearReuseableDisplayItems() { mBuilder.ClearReuseableDisplayItems(); }
    190 
    191  void AddSizeOfIncludingThis(nsWindowSizes&) const;
    192 
    193  NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
    194 
    195 private:
    196  void GetModifiedAndFramesWithProps(nsTArray<nsIFrame*>* aOutModifiedFrames,
    197                                     nsTArray<nsIFrame*>* aOutFramesWithProps);
    198 
    199  void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
    200 
    201  /**
    202   * A simple early exit heuristic to avoid slow partial display list rebuilds.
    203   * Returns true if a partial display list build should be attempted.
    204   */
    205  bool ShouldBuildPartial(nsTArray<nsIFrame*>& aModifiedFrames);
    206 
    207  /**
    208   * Recursively pre-processes the old display list tree before building the
    209   * new partial display lists, and serializes the old list into an array,
    210   * recording indices on items for fast lookup during merging. Builds an
    211   * initial linear DAG for the list if we don't have an existing one. Finds
    212   * items that have a different AGR from the specified one, and marks them to
    213   * also be built so that we get relative ordering correct. Passes
    214   * aKeepLinked=true internally for sub-lists that can't be changed to keep the
    215   * original list structure linked for fast re-use.
    216   */
    217  bool PreProcessDisplayList(
    218      RetainedDisplayList* aList, nsIFrame* aAGR, PartialUpdateResult& aUpdated,
    219      nsIFrame* aAsyncAncestor, const ActiveScrolledRoot* aAsyncAncestorASR,
    220      nsIFrame* aOuterFrame = nullptr, uint32_t aCallerKey = 0,
    221      uint32_t aNestingDepth = 0, bool aKeepLinked = false);
    222 
    223  /**
    224   * Merges items from aNewList into non-invalidated items from aOldList and
    225   * stores the result in aOutList.
    226   *
    227   * aOuterItem is a pointer to an item that owns one of the lists, if
    228   * available. If both lists are populated, then both outer items must not be
    229   * invalidated, and identical, so either can be passed here.
    230   *
    231   * Returns true if changes were made, and the resulting display list (in
    232   * aOutList) is different from aOldList.
    233   */
    234  bool MergeDisplayLists(
    235      nsDisplayList* aNewList, RetainedDisplayList* aOldList,
    236      RetainedDisplayList* aOutList,
    237      mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
    238      nsDisplayItem* aOuterItem = nullptr);
    239 
    240  bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
    241                            nsRect* aOutDirty, nsIFrame** aOutModifiedAGR,
    242                            nsTArray<nsIFrame*>& aOutFramesWithProps);
    243 
    244  bool ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
    245                    nsIFrame* aStopAtFrame,
    246                    nsTArray<nsIFrame*>& aOutFramesWithProps,
    247                    const bool aStopAtStackingContext, nsRect* aOutDirty,
    248                    nsIFrame** aOutModifiedAGR);
    249 
    250  nsIFrame* RootReferenceFrame() { return mBuilder.RootReferenceFrame(); }
    251  const nsIFrame* RootReferenceFrame() const {
    252    return mBuilder.RootReferenceFrame();
    253  }
    254 
    255  nsRect RootOverflowRect() const;
    256 
    257  /**
    258   * Tries to perform a simple partial display list build without display list
    259   * merging. In this mode, only the top-level stacking context items and their
    260   * contents are reused, when the frame subtree has not been modified.
    261   */
    262  bool TrySimpleUpdate(const nsTArray<nsIFrame*>& aModifiedFrames,
    263                       nsTArray<nsIFrame*>& aOutFramesWithProps);
    264 
    265  friend class MergeState;
    266 
    267  nsDisplayListBuilder mBuilder;
    268  RetainedDisplayList mList;
    269  RetainedDisplayListMetrics mMetrics;
    270  RetainedDisplayListData mData;
    271 };
    272 
    273 namespace RDLUtils {
    274 
    275 void AssertFrameSubtreeUnmodified(const nsIFrame* aFrame);
    276 void AssertDisplayItemUnmodified(nsDisplayItem* aItem);
    277 void AssertDisplayListUnmodified(nsDisplayList* aList);
    278 
    279 }  // namespace RDLUtils
    280 }  // namespace mozilla
    281 
    282 #endif  // RETAINEDDISPLAYLISTBUILDER_H_