summaryrefslogtreecommitdiffstats
path: root/docshell/base/BrowsingContextGroup.h
blob: 39fc6d24f8235e585fbb021a3b82aaaa85a434d7 (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
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/* -*- 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 mozilla_dom_BrowsingContextGroup_h
#define mozilla_dom_BrowsingContextGroup_h

#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/FunctionRef.h"
#include "nsRefPtrHashtable.h"
#include "nsHashKeys.h"
#include "nsTArray.h"
#include "nsTHashtable.h"
#include "nsWrapperCache.h"
#include "nsXULAppAPI.h"

namespace mozilla {
class ThrottledEventQueue;

namespace dom {

class BrowsingContext;
class WindowContext;
class ContentParent;
class DocGroup;

// A BrowsingContextGroup represents the Unit of Related Browsing Contexts in
// the standard.
//
// A BrowsingContext may not hold references to other BrowsingContext objects
// which are not in the same BrowsingContextGroup.
class BrowsingContextGroup final : public nsWrapperCache {
 public:
  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContextGroup)
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(BrowsingContextGroup)

  // Interact with the list of synced contexts. This controls the lifecycle of
  // the BrowsingContextGroup and contexts loaded within them.
  void Register(nsISupports* aContext);
  void Unregister(nsISupports* aContext);

  // Control which processes will be used to host documents loaded in this
  // BrowsingContextGroup. There should only ever be one host process per remote
  // type.
  //
  // A new host process will be subscribed to the BrowsingContextGroup unless it
  // is still launching, in which case it will subscribe itself when it is done
  // launching.
  void EnsureHostProcess(ContentParent* aProcess);

  // A removed host process will no longer be used to host documents loaded in
  // this BrowsingContextGroup.
  void RemoveHostProcess(ContentParent* aProcess);

  // Synchronize the current BrowsingContextGroup state down to the given
  // content process, and continue updating it.
  //
  // You rarely need to call this directy, as it's automatically called by
  // |EnsureHostProcess| as needed.
  void Subscribe(ContentParent* aProcess);

  // Stop synchromizing the current BrowsingContextGroup state down to a given
  // content process. The content process must no longer be a host process.
  void Unsubscribe(ContentParent* aProcess);

  // Look up the process which should be used to host documents with this
  // RemoteType. This will be a non-dead process associated with this
  // BrowsingContextGroup, if possible.
  ContentParent* GetHostProcess(const nsACString& aRemoteType);

  // When a BrowsingContext is being discarded, we may want to keep the
  // corresponding BrowsingContextGroup alive until the other process
  // acknowledges the BrowsingContext has been discarded. A `KeepAlive` will be
  // added to the `BrowsingContextGroup`, delaying destruction.
  void AddKeepAlive();
  void RemoveKeepAlive();

  // Call when we want to check if we should suspend or resume all top level
  // contexts.
  void UpdateToplevelsSuspendedIfNeeded();

  // Get a reference to the list of toplevel contexts in this
  // BrowsingContextGroup.
  nsTArray<RefPtr<BrowsingContext>>& Toplevels() { return mToplevels; }
  void GetToplevels(nsTArray<RefPtr<BrowsingContext>>& aToplevels) {
    aToplevels.AppendElements(mToplevels);
  }

  uint64_t Id() { return mId; }

  nsISupports* GetParentObject() const;
  JSObject* WrapObject(JSContext* aCx,
                       JS::Handle<JSObject*> aGivenProto) override;

  // Get or create a BrowsingContextGroup with the given ID.
  static already_AddRefed<BrowsingContextGroup> GetOrCreate(uint64_t aId);
  static already_AddRefed<BrowsingContextGroup> Create();
  static already_AddRefed<BrowsingContextGroup> Select(
      WindowContext* aParent, BrowsingContext* aOpener);

  // For each 'ContentParent', except for 'aExcludedParent',
  // associated with this group call 'aCallback'.
  template <typename Func>
  void EachOtherParent(ContentParent* aExcludedParent, Func&& aCallback) {
    MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
    for (auto iter = mSubscribers.Iter(); !iter.Done(); iter.Next()) {
      if (iter.Get()->GetKey() != aExcludedParent) {
        aCallback(iter.Get()->GetKey());
      }
    }
  }

  // For each 'ContentParent' associated with
  // this group call 'aCallback'.
  template <typename Func>
  void EachParent(Func&& aCallback) {
    MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
    for (auto iter = mSubscribers.Iter(); !iter.Done(); iter.Next()) {
      aCallback(iter.Get()->GetKey());
    }
  }

  nsresult QueuePostMessageEvent(already_AddRefed<nsIRunnable>&& aRunnable);

  void FlushPostMessageEvents();

  // Increase or decrease the suspension level in InputTaskManager
  void UpdateInputTaskManagerIfNeeded(bool aIsActive);

  static BrowsingContextGroup* GetChromeGroup();

  void GetDocGroups(nsTArray<DocGroup*>& aDocGroups);

  // Called by Document when a Document needs to be added to a DocGroup.
  already_AddRefed<DocGroup> AddDocument(const nsACString& aKey,
                                         Document* aDocument);

  // Called by Document when a Document needs to be removed to a DocGroup.
  void RemoveDocument(const nsACString& aKey, Document* aDocument);

  auto DocGroups() const { return mDocGroups.ConstIter(); }

  mozilla::ThrottledEventQueue* GetTimerEventQueue() const {
    return mTimerEventQueue;
  }

  mozilla::ThrottledEventQueue* GetWorkerEventQueue() const {
    return mWorkerEventQueue;
  }

  static void GetAllGroups(nsTArray<RefPtr<BrowsingContextGroup>>& aGroups);

  void IncInputEventSuspensionLevel();
  void DecInputEventSuspensionLevel();

 private:
  friend class CanonicalBrowsingContext;

  explicit BrowsingContextGroup(uint64_t aId);
  ~BrowsingContextGroup();

  void MaybeDestroy();
  void Destroy();

  bool ShouldSuspendAllTopLevelContexts() const;

  bool HasActiveBC();
  void DecInputTaskManagerSuspensionLevel();
  void IncInputTaskManagerSuspensionLevel();

  uint64_t mId;

  uint32_t mKeepAliveCount = 0;

#ifdef DEBUG
  bool mDestroyed = false;
#endif

  // A BrowsingContextGroup contains a series of {Browsing,Window}Context
  // objects. They are addressed using a hashtable to avoid linear lookup when
  // adding or removing elements from the set.
  //
  // FIXME: This list is only required over a counter to keep nested
  // non-discarded contexts within discarded contexts alive. It should be
  // removed in the future.
  // FIXME: Consider introducing a better common base than `nsISupports`?
  nsTHashtable<nsRefPtrHashKey<nsISupports>> mContexts;

  // The set of toplevel browsing contexts in the current BrowsingContextGroup.
  nsTArray<RefPtr<BrowsingContext>> mToplevels;

  //  Whether or not all toplevels in this group should be suspended
  bool mToplevelsSuspended = false;

  // DocGroups are thread-safe, and not able to be cycle collected,
  // but we still keep strong pointers. When all Documents are removed
  // from DocGroup (by the BrowsingContextGroup), the DocGroup is
  // removed from here.
  nsRefPtrHashtable<nsCStringHashKey, DocGroup> mDocGroups;

  // The content process which will host documents in this BrowsingContextGroup
  // which need to be loaded with a given remote type.
  //
  // A non-launching host process must also be a subscriber, though a launching
  // host process may not yet be subscribed, and a subscriber need not be a host
  // process.
  nsRefPtrHashtable<nsCStringHashKey, ContentParent> mHosts;

  nsTHashtable<nsRefPtrHashKey<ContentParent>> mSubscribers;

  // A queue to store postMessage events during page load, the queue will be
  // flushed once the page is loaded
  RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;

  RefPtr<mozilla::ThrottledEventQueue> mTimerEventQueue;
  RefPtr<mozilla::ThrottledEventQueue> mWorkerEventQueue;

  // A counter to keep track of the input event suspension level of this BCG
  //
  // We use BrowsingContextGroup to emulate process isolation in Fission, so
  // documents within the same the same BCG will behave like they share
  // the same input task queue.
  uint32_t mInputEventSuspensionLevel = 0;
  // Whether this BCG has increased the suspension level in InputTaskManager
  bool mHasIncreasedInputTaskManagerSuspensionLevel = false;
};
}  // namespace dom
}  // namespace mozilla

#endif  // !defined(mozilla_dom_BrowsingContextGroup_h)