/* -*- 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/. */
nsSHEntry::~nsSHEntry() { // Null out the mParent pointers on all our kids. for (nsISHEntry* entry : mChildren) { if (entry) {
entry->SetParent(nullptr);
}
}
}
NS_IMETHODIMP
nsSHEntry::GetTitle(nsAString& aTitle) { // Check for empty title... if (mTitle.IsEmpty() && mURI) { // Default title is the URL.
nsAutoCString spec; if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
AppendUTF8toUTF16(spec, mTitle);
}
}
NS_IMETHODIMP
nsSHEntry::GetHasUserInteraction(bool* aFlag) { // The back button and menulist deal with root/top-level // session history entries, thus we annotate only the root entry. if (!mParent) {
*aFlag = mHasUserInteraction;
} else {
nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
root->GetHasUserInteraction(aFlag);
} return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetHasUserInteraction(bool aFlag) { // The back button and menulist deal with root/top-level // session history entries, thus we annotate only the root entry. if (!mParent) {
mHasUserInteraction = aFlag;
} else {
nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(this);
root->SetHasUserInteraction(aFlag);
} return NS_OK;
}
// By default all entries are set false for subframe flag. // nsDocShell::CloneAndReplace() which creates entries for // all subframe navigations, sets the flag to true.
mShared->mIsFrameNavigation = false;
if (aOffset < 0) {
mChildren.AppendObject(aChild); return NS_OK;
}
// // Bug 52670: Ensure children are added in order. // // Later frames in the child list may load faster and get appended // before earlier frames, causing session history to be scrambled. // By growing the list here, they are added to the right position. // // Assert that aOffset will not be so high as to grow us a lot. //
NS_ASSERTION(aOffset < (mChildren.Count() + 1023), "Large frames array!\n");
// If the new child is dynamically added, try to add it to aOffset, but if // there are non-dynamically added children, the child must be after those. if (newChildIsDyn) {
int32_t lastNonDyn = aOffset - 1; for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
nsISHEntry* entry = mChildren[i]; if (entry) { if (entry->IsDynamicallyAdded()) { break;
} else {
lastNonDyn = i;
}
}
} // InsertObjectAt allows only appending one object. // If aOffset is larger than Count(), we must first manually // set the capacity. if (aOffset > mChildren.Count()) {
mChildren.SetCount(aOffset);
} if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
NS_WARNING("Adding a child failed!");
aChild->SetParent(nullptr); return NS_ERROR_FAILURE;
}
} else { // If the new child isn't dynamically added, it should be set to aOffset. // If there are dynamically added children before that, those must be // moved to be after aOffset. if (mChildren.Count() > 0) {
int32_t start = std::min(mChildren.Count() - 1, aOffset);
int32_t dynEntryIndex = -1;
nsISHEntry* dynEntry = nullptr; for (int32_t i = start; i >= 0; --i) {
nsISHEntry* entry = mChildren[i]; if (entry) { if (entry->IsDynamicallyAdded()) {
dynEntryIndex = i;
dynEntry = entry;
} else { break;
}
}
}
// Make sure there isn't anything at aOffset. if (aOffset < mChildren.Count()) {
nsISHEntry* oldChild = mChildren[aOffset]; if (oldChild && oldChild != aChild) { // Under Fission, this can happen when a network-created iframe starts // out in-process, moves out-of-process, and then switches back. At that // point, we'll create a new network-created DocShell at the same index // where we already have an entry for the original network-created // DocShell. // // This should ideally stop being an issue once the Fission-aware // session history rewrite is complete.
NS_ASSERTION(
aUseRemoteSubframes, "Adding a child where we already have a child? This may misbehave");
oldChild->SetParent(nullptr);
}
}
mChildren.ReplaceObjectAt(aChild, aOffset);
}
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::RemoveChild(nsISHEntry* aChild) {
NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE); bool childRemoved = false; if (aChild->IsDynamicallyAdded()) {
childRemoved = mChildren.RemoveObject(aChild);
} else {
int32_t index = mChildren.IndexOfObject(aChild); if (index >= 0) { // Other alive non-dynamic child docshells still keep mChildOffset, // so we don't want to change the indices here.
mChildren.ReplaceObjectAt(nullptr, index);
childRemoved = true;
}
} if (childRemoved) {
aChild->SetParent(nullptr);
// reduce the child count, i.e. remove empty children at the end for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) { if (!mChildren.RemoveObjectAt(i)) { break;
}
}
} return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry** aResult) { if (aIndex >= 0 && aIndex < mChildren.Count()) {
*aResult = mChildren[aIndex]; // yes, mChildren can have holes in it. AddChild's offset parameter makes // that possible.
NS_IF_ADDREF(*aResult);
} else {
*aResult = nullptr;
} return NS_OK;
}
bool dynamicallyAddedChild = false;
HasDynamicallyAddedChild(&dynamicallyAddedChild); if (dynamicallyAddedChild) { return;
}
// If the user did a shift-reload on this frameset page, // we don't want to load the subframes from history. if (IsForceReloadType(mLoadType) || mLoadType == LOAD_REFRESH) { return;
}
/* Before looking for the subframe's url, check * the expiration status of the parent. If the parent * has expired from cache, then subframes will not be * loaded from history in certain situations. * If the user pressed reload and the parent frame has expired * from cache, we do not want to load the child frame from history.
*/ if (mShared->mExpired && (mLoadType == LOAD_RELOAD_NORMAL)) { // The parent has expired. Return null.
*aChild = nullptr; return;
} // Get the child subframe from session history.
GetChildAt(aChildOffset, aChild); if (*aChild) { // Set the parent's Load Type on the child
(*aChild)->SetLoadType(mLoadType);
}
}
for (int32_t i = 0; i < mChildren.Count(); ++i) { if (mChildren[i]) {
nsID childDocshellID;
nsresult rv = mChildren[i]->GetDocshellID(childDocshellID);
NS_ENSURE_SUCCESS(rv, rv); if (docshellID == childDocshellID) {
mChildren[i]->SetParent(nullptr);
mChildren.ReplaceObjectAt(aNewEntry, i); return aNewEntry->SetParent(this);
}
}
} return NS_ERROR_FAILURE;
}
NS_IMETHODIMP_(void) nsSHEntry::ClearEntry() {
int32_t childCount = GetChildCount(); // Remove all children of this entry for (int32_t i = childCount - 1; i >= 0; i--) {
nsCOMPtr<nsISHEntry> child;
GetChildAt(i, getter_AddRefs(child));
RemoveChild(child);
}
AbandonBFCacheEntry();
}
NS_IMETHODIMP
nsSHEntry::SetShistory(nsISHistory* aSHistory) {
nsWeakPtr shistory = do_GetWeakReference(aSHistory); // mSHistory can not be changed once it's set
MOZ_ASSERT(!mShared->mSHistory || (mShared->mSHistory == shistory));
mShared->mSHistory = shistory; return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetLoadTypeAsHistory() { // Set the LoadType by default to loadHistory during creation
mLoadType = LOAD_HISTORY; return NS_OK;
}
// Do not inherit principal from document (security-critical!);
uint32_t flags = nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_NONE;
// Passing nullptr as aSourceDocShell gives the same behaviour as before // aSourceDocShell was introduced. According to spec we should be passing // the source browsing context that was used when the history entry was // first created. bug 947716 has been created to address this issue.
nsAutoString srcdoc;
nsCOMPtr<nsIURI> baseURI; if (GetIsSrcdocEntry()) {
GetSrcdocData(srcdoc);
baseURI = GetBaseURI();
flags |= nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
} else {
srcdoc = VoidString();
}
loadState->SetSrcdocData(srcdoc);
loadState->SetBaseURI(baseURI);
loadState->SetInternalLoadFlags(flags);
// When we create a load state from the history entry we already know if // https-first was able to upgrade the request from http to https. There is no // point in re-retrying to upgrade.
loadState->SetIsExemptFromHTTPSFirstMode(true);
loadState.forget(aLoadState); return NS_OK;
}
NS_IMETHODIMP_(void)
nsSHEntry::SyncTreesForSubframeNavigation(
nsISHEntry* aEntry, mozilla::dom::BrowsingContext* aTopBC,
mozilla::dom::BrowsingContext* aIgnoreBC) { // XXX Keep this in sync with // SessionHistoryEntry::SyncTreesForSubframeNavigation // // We need to sync up the browsing context and session history trees for // subframe navigation. If the load was in a subframe, we forward up to // the top browsing context, which will then recursively sync up all browsing // contexts to their corresponding entries in the new session history tree. If // we don't do this, then we can cache a content viewer on the wrong cloned // entry, and subsequently restore it at the wrong time.
nsCOMPtr<nsISHEntry> newRootEntry = nsSHistory::GetRootSHEntry(aEntry); if (newRootEntry) { // newRootEntry is now the new root entry. // Find the old root entry as well.
// Need a strong ref. on |oldRootEntry| so it isn't destroyed when // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
nsCOMPtr<nsISHEntry> oldRootEntry = nsSHistory::GetRootSHEntry(this);
if (oldRootEntry) {
nsSHistory::SwapEntriesData data = {aIgnoreBC, newRootEntry, nullptr};
nsSHistory::SetChildHistoryEntry(oldRootEntry, aTopBC, 0, &data);
}
}
}
void nsSHEntry::EvictDocumentViewer() {
nsCOMPtr<nsIDocumentViewer> viewer = GetDocumentViewer(); if (viewer) {
mShared->NotifyListenersDocumentViewerEvicted(); // Drop the presentation state before destroying the viewer, so that // document teardown is able to correctly persist the state.
SetDocumentViewer(nullptr);
SyncPresentationState();
viewer->Destroy();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.