Bug 1888590 - Mark some subtests on trusted-types-event-handlers.html as failing...
[gecko.git] / docshell / shistory / ChildSHistory.cpp
blob3e3cf09493d7706e94d938c81fa66e12e2d1ece8
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/. */
7 #include "mozilla/dom/ChildSHistory.h"
8 #include "mozilla/dom/ChildSHistoryBinding.h"
9 #include "mozilla/dom/CanonicalBrowsingContext.h"
10 #include "mozilla/dom/ContentChild.h"
11 #include "mozilla/dom/ContentFrameMessageManager.h"
12 #include "nsIXULRuntime.h"
13 #include "nsComponentManagerUtils.h"
14 #include "nsSHEntry.h"
15 #include "nsSHistory.h"
16 #include "nsDocShell.h"
17 #include "nsXULAppAPI.h"
19 extern mozilla::LazyLogModule gSHLog;
21 namespace mozilla {
22 namespace dom {
24 ChildSHistory::ChildSHistory(BrowsingContext* aBrowsingContext)
25 : mBrowsingContext(aBrowsingContext) {}
27 ChildSHistory::~ChildSHistory() {
28 if (mHistory) {
29 static_cast<nsSHistory*>(mHistory.get())->SetBrowsingContext(nullptr);
33 void ChildSHistory::SetBrowsingContext(BrowsingContext* aBrowsingContext) {
34 mBrowsingContext = aBrowsingContext;
37 void ChildSHistory::SetIsInProcess(bool aIsInProcess) {
38 if (!aIsInProcess) {
39 MOZ_ASSERT_IF(mozilla::SessionHistoryInParent(), !mHistory);
40 if (!mozilla::SessionHistoryInParent()) {
41 RemovePendingHistoryNavigations();
42 if (mHistory) {
43 static_cast<nsSHistory*>(mHistory.get())->SetBrowsingContext(nullptr);
44 mHistory = nullptr;
48 return;
51 if (mHistory || mozilla::SessionHistoryInParent()) {
52 return;
55 mHistory = new nsSHistory(mBrowsingContext);
58 int32_t ChildSHistory::Count() {
59 if (mozilla::SessionHistoryInParent()) {
60 uint32_t length = mLength;
61 for (uint32_t i = 0; i < mPendingSHistoryChanges.Length(); ++i) {
62 length += mPendingSHistoryChanges[i].mLengthDelta;
65 return length;
67 return mHistory->GetCount();
70 int32_t ChildSHistory::Index() {
71 if (mozilla::SessionHistoryInParent()) {
72 uint32_t index = mIndex;
73 for (uint32_t i = 0; i < mPendingSHistoryChanges.Length(); ++i) {
74 index += mPendingSHistoryChanges[i].mIndexDelta;
77 return index;
79 int32_t index;
80 mHistory->GetIndex(&index);
81 return index;
84 nsID ChildSHistory::AddPendingHistoryChange() {
85 int32_t indexDelta = 1;
86 int32_t lengthDelta = (Index() + indexDelta) - (Count() - 1);
87 return AddPendingHistoryChange(indexDelta, lengthDelta);
90 nsID ChildSHistory::AddPendingHistoryChange(int32_t aIndexDelta,
91 int32_t aLengthDelta) {
92 nsID changeID = nsID::GenerateUUID();
93 PendingSHistoryChange change = {changeID, aIndexDelta, aLengthDelta};
94 mPendingSHistoryChanges.AppendElement(change);
95 return changeID;
98 void ChildSHistory::SetIndexAndLength(uint32_t aIndex, uint32_t aLength,
99 const nsID& aChangeID) {
100 mIndex = aIndex;
101 mLength = aLength;
102 mPendingSHistoryChanges.RemoveElementsBy(
103 [aChangeID](const PendingSHistoryChange& aChange) {
104 return aChange.mChangeID == aChangeID;
108 void ChildSHistory::Reload(uint32_t aReloadFlags, ErrorResult& aRv) {
109 if (mozilla::SessionHistoryInParent()) {
110 if (XRE_IsParentProcess()) {
111 nsCOMPtr<nsISHistory> shistory =
112 mBrowsingContext->Canonical()->GetSessionHistory();
113 if (shistory) {
114 aRv = shistory->Reload(aReloadFlags);
116 } else {
117 ContentChild::GetSingleton()->SendHistoryReload(mBrowsingContext,
118 aReloadFlags);
121 return;
123 nsCOMPtr<nsISHistory> shistory = mHistory;
124 aRv = shistory->Reload(aReloadFlags);
127 bool ChildSHistory::CanGo(int32_t aOffset) {
128 CheckedInt<int32_t> index = Index();
129 index += aOffset;
130 if (!index.isValid()) {
131 return false;
133 return index.value() < Count() && index.value() >= 0;
136 void ChildSHistory::Go(int32_t aOffset, bool aRequireUserInteraction,
137 bool aUserActivation, ErrorResult& aRv) {
138 CheckedInt<int32_t> index = Index();
139 MOZ_LOG(
140 gSHLog, LogLevel::Debug,
141 ("ChildSHistory::Go(%d), current index = %d", aOffset, index.value()));
142 if (aRequireUserInteraction && aOffset != -1 && aOffset != 1) {
143 NS_ERROR(
144 "aRequireUserInteraction may only be used with an offset of -1 or 1");
145 aRv.Throw(NS_ERROR_INVALID_ARG);
146 return;
149 while (true) {
150 index += aOffset;
151 if (!index.isValid()) {
152 aRv.Throw(NS_ERROR_FAILURE);
153 return;
156 // Check for user interaction if desired, except for the first and last
157 // history entries. We compare with >= to account for the case where
158 // aOffset >= Count().
159 if (!StaticPrefs::browser_navigation_requireUserInteraction() ||
160 !aRequireUserInteraction || index.value() >= Count() - 1 ||
161 index.value() <= 0) {
162 break;
164 if (mHistory && mHistory->HasUserInteractionAtIndex(index.value())) {
165 break;
169 GotoIndex(index.value(), aOffset, aRequireUserInteraction, aUserActivation,
170 aRv);
173 void ChildSHistory::AsyncGo(int32_t aOffset, bool aRequireUserInteraction,
174 bool aUserActivation, CallerType aCallerType,
175 ErrorResult& aRv) {
176 CheckedInt<int32_t> index = Index();
177 MOZ_LOG(gSHLog, LogLevel::Debug,
178 ("ChildSHistory::AsyncGo(%d), current index = %d", aOffset,
179 index.value()));
180 nsresult rv = mBrowsingContext->CheckLocationChangeRateLimit(aCallerType);
181 if (NS_FAILED(rv)) {
182 MOZ_LOG(gSHLog, LogLevel::Debug, ("Rejected"));
183 aRv.Throw(rv);
184 return;
187 RefPtr<PendingAsyncHistoryNavigation> asyncNav =
188 new PendingAsyncHistoryNavigation(this, aOffset, aRequireUserInteraction,
189 aUserActivation);
190 mPendingNavigations.insertBack(asyncNav);
191 NS_DispatchToCurrentThread(asyncNav.forget());
194 void ChildSHistory::GotoIndex(int32_t aIndex, int32_t aOffset,
195 bool aRequireUserInteraction,
196 bool aUserActivation, ErrorResult& aRv) {
197 MOZ_LOG(gSHLog, LogLevel::Debug,
198 ("ChildSHistory::GotoIndex(%d, %d), epoch %" PRIu64, aIndex, aOffset,
199 mHistoryEpoch));
200 if (mozilla::SessionHistoryInParent()) {
201 if (!mPendingEpoch) {
202 mPendingEpoch = true;
203 RefPtr<ChildSHistory> self(this);
204 NS_DispatchToCurrentThread(
205 NS_NewRunnableFunction("UpdateEpochRunnable", [self] {
206 self->mHistoryEpoch++;
207 self->mPendingEpoch = false;
208 }));
211 nsCOMPtr<nsISHistory> shistory = mHistory;
212 RefPtr<BrowsingContext> bc = mBrowsingContext;
213 bc->HistoryGo(
214 aOffset, mHistoryEpoch, aRequireUserInteraction, aUserActivation,
215 [shistory](Maybe<int32_t>&& aRequestedIndex) {
216 // FIXME Should probably only do this for non-fission.
217 if (aRequestedIndex.isSome() && shistory) {
218 shistory->InternalSetRequestedIndex(aRequestedIndex.value());
221 } else {
222 nsCOMPtr<nsISHistory> shistory = mHistory;
223 aRv = shistory->GotoIndex(aIndex, aUserActivation);
227 void ChildSHistory::RemovePendingHistoryNavigations() {
228 // Per the spec, this generally shouldn't remove all navigations - it
229 // depends if they're in the same document family or not. We don't do
230 // that. Also with SessionHistoryInParent, this can only abort AsyncGo's
231 // that have not yet been sent to the parent - see discussion of point
232 // 2.2 in comments in nsDocShell::UpdateURLAndHistory()
233 MOZ_LOG(gSHLog, LogLevel::Debug,
234 ("ChildSHistory::RemovePendingHistoryNavigations: %zu",
235 mPendingNavigations.length()));
236 mPendingNavigations.clear();
239 void ChildSHistory::EvictLocalDocumentViewers() {
240 if (!mozilla::SessionHistoryInParent()) {
241 mHistory->EvictAllDocumentViewers();
245 nsISHistory* ChildSHistory::GetLegacySHistory(ErrorResult& aError) {
246 if (mozilla::SessionHistoryInParent()) {
247 aError.ThrowTypeError(
248 "legacySHistory is not available with session history in the parent.");
249 return nullptr;
252 MOZ_RELEASE_ASSERT(mHistory);
253 return mHistory;
256 nsISHistory* ChildSHistory::LegacySHistory() {
257 IgnoredErrorResult ignore;
258 nsISHistory* shistory = GetLegacySHistory(ignore);
259 MOZ_RELEASE_ASSERT(shistory);
260 return shistory;
263 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChildSHistory)
264 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
265 NS_INTERFACE_MAP_ENTRY(nsISupports)
266 NS_INTERFACE_MAP_END
268 NS_IMPL_CYCLE_COLLECTING_ADDREF(ChildSHistory)
269 NS_IMPL_CYCLE_COLLECTING_RELEASE(ChildSHistory)
271 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ChildSHistory)
273 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ChildSHistory)
274 if (tmp->mHistory) {
275 static_cast<nsSHistory*>(tmp->mHistory.get())->SetBrowsingContext(nullptr);
277 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext, mHistory)
278 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
279 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
281 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ChildSHistory)
282 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext, mHistory)
283 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
285 JSObject* ChildSHistory::WrapObject(JSContext* cx,
286 JS::Handle<JSObject*> aGivenProto) {
287 return ChildSHistory_Binding::Wrap(cx, this, aGivenProto);
290 nsISupports* ChildSHistory::GetParentObject() const {
291 return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
294 } // namespace dom
295 } // namespace mozilla