DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b0b856065d5b)

VCS Links

HistoryTracker

SwapEntriesData

nsSHistory

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
/* -*- 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 nsSHistory_h
#define nsSHistory_h

#include "nsCOMPtr.h"
#include "nsExpirationTracker.h"
#include "nsISHistory.h"
#include "nsSHEntryShared.h"
#include "nsSimpleEnumerator.h"
#include "nsTObserverArray.h"
#include "nsWeakReference.h"

#include "mozilla/LinkedList.h"
#include "mozilla/UniquePtr.h"

class nsIDocShell;
class nsDocShell;
class nsSHistoryObserver;
class nsISHEntry;

class nsSHistory final : public mozilla::LinkedListElement<nsSHistory>,
                         public nsISHistory,
                         public nsSupportsWeakReference
{
public:

  // The timer based history tracker is used to evict bfcache on expiration.
  class HistoryTracker final : public nsExpirationTracker<nsSHEntryShared, 3>
  {
  public:
    explicit HistoryTracker(nsSHistory* aSHistory,
                            uint32_t aTimeout,
                            nsIEventTarget* aEventTarget)
      : nsExpirationTracker(1000 * aTimeout / 2, "HistoryTracker", aEventTarget)
    {
      MOZ_ASSERT(aSHistory);
      mSHistory = aSHistory;
    }

  protected:
    virtual void NotifyExpired(nsSHEntryShared* aObj) override
    {
      RemoveObject(aObj);
      mSHistory->EvictExpiredContentViewerForEntry(aObj);
    }

  private:
    // HistoryTracker is owned by nsSHistory; it always outlives HistoryTracker
    // so it's safe to use raw pointer here.
    nsSHistory* mSHistory;
  };

  // Structure used in SetChildHistoryEntry
  struct SwapEntriesData
  {
    nsDocShell* ignoreShell;     // constant; the shell to ignore
    nsISHEntry* destTreeRoot;    // constant; the root of the dest tree
    nsISHEntry* destTreeParent;  // constant; the node under destTreeRoot
                                 // whose children will correspond to aEntry
  };

  nsSHistory();
  NS_DECL_ISUPPORTS
  NS_DECL_NSISHISTORY

  nsresult Reload(uint32_t aReloadFlags);
  nsresult GetCurrentURI(nsIURI** aResultURI);

  // One time initialization method called upon docshell module construction
  static nsresult Startup();
  static void Shutdown();
  static void UpdatePrefs();

  // Max number of total cached content viewers.  If the pref
  // browser.sessionhistory.max_total_viewers is negative, then
  // this value is calculated based on the total amount of memory.
  // Otherwise, it comes straight from the pref.
  static uint32_t GetMaxTotalViewers() { return sHistoryMaxTotalViewers; }

  // Get the root SHEntry from a given entry.
  static nsISHEntry* GetRootSHEntry(nsISHEntry* aEntry);

  // Callback prototype for WalkHistoryEntries.
  // aEntry is the child history entry, aShell is its corresponding docshell,
  // aChildIndex is the child's index in its parent entry, and aData is
  // the opaque pointer passed to WalkHistoryEntries.
  typedef nsresult(*WalkHistoryEntriesFunc)(nsISHEntry* aEntry,
                                            nsDocShell* aShell,
                                            int32_t aChildIndex,
                                            void* aData);

  // Clone a session history tree for subframe navigation.
  // The tree rooted at |aSrcEntry| will be cloned into |aDestEntry|, except
  // for the entry with id |aCloneID|, which will be replaced with
  // |aReplaceEntry|. |aSrcShell| is a (possibly null) docshell which
  // corresponds to |aSrcEntry| via its mLSHE or mOHE pointers, and will
  // have that pointer updated to point to the cloned history entry.
  // If aCloneChildren is true then the children of the entry with id
  // |aCloneID| will be cloned into |aReplaceEntry|.
  static nsresult CloneAndReplace(nsISHEntry* aSrcEntry,
                                  nsDocShell* aSrcShell,
                                  uint32_t aCloneID,
                                  nsISHEntry* aReplaceEntry,
                                  bool aCloneChildren,
                                  nsISHEntry** aDestEntry);

  // Child-walking callback for CloneAndReplace
  static nsresult CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell,
                                       int32_t aChildIndex, void* aData);


  // Child-walking callback for SetHistoryEntry
  static nsresult SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell,
                                       int32_t aEntryIndex, void* aData);

  // For each child of aRootEntry, find the corresponding docshell which is
  // a child of aRootShell, and call aCallback. The opaque pointer aData
  // is passed to the callback.
  static nsresult WalkHistoryEntries(nsISHEntry* aRootEntry,
                                     nsDocShell* aRootShell,
                                     WalkHistoryEntriesFunc aCallback,
                                     void* aData);

private:
  virtual ~nsSHistory();
  friend class nsSHistoryObserver;

  // The size of the window of SHEntries which can have alive viewers in the
  // bfcache around the currently active SHEntry.
  //
  // We try to keep viewers for SHEntries between index - VIEWER_WINDOW and
  // index + VIEWER_WINDOW alive.
  static const int32_t VIEWER_WINDOW = 3;

  nsresult LoadDifferingEntries(nsISHEntry* aPrevEntry, nsISHEntry* aNextEntry,
                                nsIDocShell* aRootDocShell, long aLoadType,
                                bool& aDifferenceFound);
  nsresult InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
                        long aLoadType);

  nsresult LoadEntry(int32_t aIndex, long aLoadType, uint32_t aHistCmd);

#ifdef DEBUG
  nsresult PrintHistory();
#endif

  // Find the history entry for a given bfcache entry. It only looks up between
  // the range where alive viewers may exist (i.e nsSHistory::VIEWER_WINDOW).
  nsresult FindEntryForBFCache(nsIBFCacheEntry* aBFEntry,
                               nsISHEntry** aResult,
                               int32_t* aResultIndex);

  // Evict content viewers in this window which don't lie in the "safe" range
  // around aIndex.
  void EvictOutOfRangeWindowContentViewers(int32_t aIndex);
  void EvictContentViewerForEntry(nsISHEntry* aEntry);
  static void GloballyEvictContentViewers();
  static void GloballyEvictAllContentViewers();

  // Calculates a max number of total
  // content viewers to cache, based on amount of total memory
  static uint32_t CalcMaxTotalViewers();

  nsresult LoadNextPossibleEntry(int32_t aNewIndex, long aLoadType,
                                 uint32_t aHistCmd);

  // aIndex is the index of the entry which may be removed.
  // If aKeepNext is true, aIndex is compared to aIndex + 1,
  // otherwise comparison is done to aIndex - 1.
  bool RemoveDuplicate(int32_t aIndex, bool aKeepNext);

  // Track all bfcache entries and evict on expiration.
  mozilla::UniquePtr<HistoryTracker> mHistoryTracker;

  nsTArray<nsCOMPtr<nsISHEntry>> mEntries; // entries are never null
  int32_t mIndex;           // -1 means "no index"
  int32_t mRequestedIndex;  // -1 means "no requested index"

  void WindowIndices(int32_t aIndex, int32_t* aOutStartIndex,
                     int32_t* aOutEndIndex);

  // Length of mEntries.
  int32_t Length() { return int32_t(mEntries.Length()); }

  // Session History listeners
  nsAutoTObserverArray<nsWeakPtr, 2> mListeners;

  // Weak reference. Do not refcount this.
  nsIDocShell* mRootDocShell;

  // Max viewers allowed total, across all SHistory objects
  static int32_t sHistoryMaxTotalViewers;
};

inline nsISupports*
ToSupports(nsSHistory* aObj)
{
  return static_cast<nsISHistory*>(aObj);
}

#endif /* nsSHistory */