summaryrefslogtreecommitdiffstats
path: root/docshell/shistory/ChildSHistory.h
blob: 43b2f63bd03bdde916b124110c9b5aa475a946a0 (plain)
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
/* -*- 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/. */

/**
 * ChildSHistory represents a view of session history from a child process. It
 * exposes getters for some cached history state, and mutators which are
 * implemented by communicating with the actual history storage.
 *
 * NOTE: Currently session history is in transition, meaning that we're still
 * using the legacy nsSHistory class internally. The API exposed from this class
 * should be only the API which we expect to expose when this transition is
 * complete, and special cases will need to call through the LegacySHistory()
 * getters.
 */

#ifndef mozilla_dom_ChildSHistory_h
#define mozilla_dom_ChildSHistory_h

#include "nsCOMPtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsWrapperCache.h"
#include "nsThreadUtils.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/LinkedList.h"
#include "nsID.h"

class nsISHEntry;
class nsISHistory;

namespace mozilla {
namespace dom {

class BrowsingContext;

class ChildSHistory : public nsISupports, public nsWrapperCache {
 public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ChildSHistory)
  nsISupports* GetParentObject() const;
  JSObject* WrapObject(JSContext* cx,
                       JS::Handle<JSObject*> aGivenProto) override;

  explicit ChildSHistory(BrowsingContext* aBrowsingContext);

  void SetBrowsingContext(BrowsingContext* aBrowsingContext);

  // Create or destroy the session history implementation in the child process.
  // This can be removed once session history is stored exclusively in the
  // parent process.
  void SetIsInProcess(bool aIsInProcess);
  bool IsInProcess() { return !!mHistory; }

  int32_t Count();
  int32_t Index();

  /**
   * Reload the current entry in the session history.
   */
  void Reload(uint32_t aReloadFlags, ErrorResult& aRv);

  /**
   * The CanGo and Go methods are called with an offset from the current index.
   * Positive numbers go forward in history, while negative numbers go
   * backwards.
   */
  bool CanGo(int32_t aOffset);
  void Go(int32_t aOffset, bool aRequireUserInteraction, ErrorResult& aRv);
  void AsyncGo(int32_t aOffset, bool aRequireUserInteraction,
               CallerType aCallerType, ErrorResult& aRv);

  // aIndex is the new index, and aOffset is the offset between new and current.
  void GotoIndex(int32_t aIndex, int32_t aOffset, bool aRequireUserInteraction,
                 ErrorResult& aRv);

  void RemovePendingHistoryNavigations();

  /**
   * Evicts all content viewers within the current process.
   */
  void EvictLocalContentViewers();

  // GetLegacySHistory and LegacySHistory have been deprecated. Don't
  // use these, but instead handle the interaction with nsISHistory in
  // the parent process.
  nsISHistory* GetLegacySHistory(ErrorResult& aError);
  nsISHistory* LegacySHistory();

  void SetIndexAndLength(uint32_t aIndex, uint32_t aLength,
                         const nsID& aChangeId);
  nsID AddPendingHistoryChange();
  nsID AddPendingHistoryChange(int32_t aIndexDelta, int32_t aLengthDelta);

  // AsyncHistoryLength is for testing.
  void SetAsyncHistoryLength(bool aEnable, ErrorResult& aRv);
  bool AsyncHistoryLength() { return mAsyncHistoryLength; }

 private:
  virtual ~ChildSHistory() = default;

  class PendingAsyncHistoryNavigation
      : public Runnable,
        public mozilla::LinkedListElement<PendingAsyncHistoryNavigation> {
   public:
    PendingAsyncHistoryNavigation(ChildSHistory* aHistory, int32_t aOffset,
                                  bool aRequireUserInteraction)
        : Runnable("PendingAsyncHistoryNavigation"),
          mHistory(aHistory),
          mRequireUserInteraction(aRequireUserInteraction),
          mOffset(aOffset) {}

    NS_IMETHOD Run() override {
      if (isInList()) {
        remove();
        mHistory->Go(mOffset, mRequireUserInteraction, IgnoreErrors());
      }
      return NS_OK;
    }

   private:
    RefPtr<ChildSHistory> mHistory;
    bool mRequireUserInteraction;
    int32_t mOffset;
  };

  RefPtr<BrowsingContext> mBrowsingContext;
  nsCOMPtr<nsISHistory> mHistory;
  // Can be removed once history-in-parent is the only way
  mozilla::LinkedList<PendingAsyncHistoryNavigation> mPendingNavigations;
  int32_t mIndex = -1;
  int32_t mLength = 0;

  struct PendingSHistoryChange {
    nsID mChangeID;
    int32_t mIndexDelta;
    int32_t mLengthDelta;
  };
  AutoTArray<PendingSHistoryChange, 2> mPendingSHistoryChanges;

  bool mAsyncHistoryLength = false;

  // Needs to start 1 above default epoch in parent
  uint64_t mHistoryEpoch = 1;
  bool mPendingEpoch = false;
};

}  // namespace dom
}  // namespace mozilla

#endif /* mozilla_dom_ChildSHistory_h */