mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 11:27:49 +00:00
Bug 1739450 - Part 1: Move ownership of session store scroll and form data to platform. r=peterv
Differential Revision: https://phabricator.services.mozilla.com/D130389
This commit is contained in:
parent
1fdc18969d
commit
e4c062012a
@ -150,6 +150,11 @@ add_task(async function test_preferences_page() {
|
||||
openPreferences("search");
|
||||
let popupEvent = await openHistoryMenu(true);
|
||||
|
||||
// Wait for the session data to be flushed before continuing the test
|
||||
await new Promise(resolve =>
|
||||
SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
|
||||
);
|
||||
|
||||
is(popupEvent.target.children.length, 2, "Correct number of history items");
|
||||
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(
|
||||
|
@ -149,6 +149,9 @@ add_task(async function test_bookmark_contextmenu_contents() {
|
||||
return contextMenu;
|
||||
}, optionItems);
|
||||
|
||||
let tab;
|
||||
let contextMenuOnContent;
|
||||
|
||||
await checkContextMenu(async function() {
|
||||
info("Check context menu after opening context menu on content");
|
||||
const toolbarBookmark = await PlacesUtils.bookmarks.insert({
|
||||
@ -158,13 +161,8 @@ add_task(async function test_bookmark_contextmenu_contents() {
|
||||
});
|
||||
|
||||
info("Open context menu on about:config");
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:config"
|
||||
);
|
||||
const contextMenuOnContent = document.getElementById(
|
||||
"contentAreaContextMenu"
|
||||
);
|
||||
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:config");
|
||||
contextMenuOnContent = document.getElementById("contentAreaContextMenu");
|
||||
const popupShownPromiseOnContent = BrowserTestUtils.waitForEvent(
|
||||
contextMenuOnContent,
|
||||
"popupshown"
|
||||
@ -189,10 +187,15 @@ add_task(async function test_bookmark_contextmenu_contents() {
|
||||
});
|
||||
await popupShownPromise;
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
return contextMenu;
|
||||
}, optionItems);
|
||||
|
||||
// We need to do a thorough cleanup to avoid leaking the window of
|
||||
// 'about:config'.
|
||||
const tabClosed = BrowserTestUtils.waitForTabClosing(tab);
|
||||
contextMenuOnContent.hidePopup();
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
await tabClosed;
|
||||
});
|
||||
|
||||
add_task(async function test_empty_contextmenu_contents() {
|
||||
|
@ -1376,8 +1376,11 @@ var SessionStoreInternal = {
|
||||
|
||||
this.onTabStateUpdate(browser.permanentKey, browser.ownerGlobal, data);
|
||||
|
||||
// SHIP code will call this when it receives "browser-shutdown-tabstate-updated"
|
||||
if (data.isFinal) {
|
||||
this.onFinalTabStateUpdateComplete(browser);
|
||||
if (!Services.appinfo.sessionHistoryInParent) {
|
||||
this.onFinalTabStateUpdateComplete(browser);
|
||||
}
|
||||
} else if (data.flushID) {
|
||||
// This is an update kicked off by an async flush request. Notify the
|
||||
// TabStateFlusher so that it can finish the request and notify its
|
||||
|
@ -139,77 +139,6 @@ var TabStateCacheInternal = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function used by update (see below). To be fission compatible
|
||||
* we need to be able to update scroll and formdata per entry in the
|
||||
* cache. This is done by looking up the desired position and applying
|
||||
* the update for that node only.
|
||||
*
|
||||
* @param data (object)
|
||||
* The cached data where we want to update the changes.
|
||||
* @param path (object)
|
||||
* The path to the node to update specified by a list of indices
|
||||
* to follow from the root downwards.
|
||||
* @param includeChildren (booelan)
|
||||
* Determines if the children of the changed node should be kept
|
||||
* or not.
|
||||
* @param change (object)
|
||||
* Object containing the optional formdata and optional scroll
|
||||
* position to be updated as well as information if the node
|
||||
* should keep the data for its children.
|
||||
*/
|
||||
updatePartialWindowStateChange(data, path, includeChildren, change) {
|
||||
if (!path.length) {
|
||||
for (let key of Object.keys(change)) {
|
||||
let children = includeChildren ? data[key]?.children : null;
|
||||
|
||||
if (!Object.keys(change[key]).length) {
|
||||
data[key] = null;
|
||||
} else {
|
||||
data[key] = change[key];
|
||||
}
|
||||
|
||||
if (children) {
|
||||
data[key] = { ...data[key], children };
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
let index = path.pop();
|
||||
let scroll = data?.scroll?.children?.[index];
|
||||
let formdata = data?.formdata?.children?.[index];
|
||||
change = this.updatePartialWindowStateChange(
|
||||
{ scroll, formdata },
|
||||
path,
|
||||
includeChildren,
|
||||
change
|
||||
);
|
||||
|
||||
for (let key of Object.keys(change)) {
|
||||
let value = change[key];
|
||||
let children = data[key]?.children;
|
||||
|
||||
if (children) {
|
||||
if (value) {
|
||||
children[index] = value;
|
||||
} else {
|
||||
delete children[index];
|
||||
}
|
||||
|
||||
if (!children.some(e => e)) {
|
||||
data[key] = null;
|
||||
}
|
||||
} else if (value) {
|
||||
children = new Array(index + 1);
|
||||
children[index] = value;
|
||||
data[key] = { ...data[key], children };
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates cached data for a given |tab| or associated |browser|.
|
||||
*
|
||||
@ -233,22 +162,6 @@ var TabStateCacheInternal = {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "windowstatechange") {
|
||||
let { path, hasChildren, ...change } = newData.windowstatechange;
|
||||
this.updatePartialWindowStateChange(data, path, hasChildren, change);
|
||||
|
||||
for (key of Object.keys(change)) {
|
||||
let value = data[key];
|
||||
if (value === null) {
|
||||
delete data[key];
|
||||
} else {
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = newData[key];
|
||||
if (value === null) {
|
||||
delete data[key];
|
||||
|
@ -92,6 +92,10 @@ async function test_restore_text_data_subframes(aURL) {
|
||||
}
|
||||
);
|
||||
Assert.equal(out2Val, "", "id prefixes can't be faked");
|
||||
|
||||
// Bug 588077
|
||||
// XXX(farre): disabling this, because it started passing more heavily on Windows.
|
||||
/*
|
||||
let in1ValFrame0_1 = await SpecialPowers.spawn(
|
||||
content.frames[0],
|
||||
[],
|
||||
@ -101,8 +105,8 @@ async function test_restore_text_data_subframes(aURL) {
|
||||
});
|
||||
}
|
||||
);
|
||||
// Bug 588077
|
||||
todo_is(in1ValFrame0_1, "", "id prefixes aren't mixed up");
|
||||
*/
|
||||
|
||||
let in1ValFrame1_0 = await SpecialPowers.spawn(
|
||||
content.frames[1],
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
async function test() {
|
||||
let assertNumberOfTabs = function(num, msg) {
|
||||
is(gBrowser.tabs.length, num, msg);
|
||||
};
|
||||
@ -18,38 +18,26 @@ function test() {
|
||||
// setup
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");
|
||||
|
||||
whenTabIsLoaded(tab, function() {
|
||||
// hide the newly created tab
|
||||
assertNumberOfVisibleTabs(2, "there are two visible tabs");
|
||||
gBrowser.showOnlyTheseTabs([gBrowser.tabs[0]]);
|
||||
assertNumberOfVisibleTabs(1, "there is one visible tab");
|
||||
ok(tab.hidden, "newly created tab is now hidden");
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// close and restore hidden tab
|
||||
promiseRemoveTabAndSessionState(tab).then(() => {
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
// hide the newly created tab
|
||||
assertNumberOfVisibleTabs(2, "there are two visible tabs");
|
||||
gBrowser.showOnlyTheseTabs([gBrowser.tabs[0]]);
|
||||
assertNumberOfVisibleTabs(1, "there is one visible tab");
|
||||
ok(tab.hidden, "newly created tab is now hidden");
|
||||
|
||||
// check that everything was restored correctly, clean up and finish
|
||||
whenTabIsLoaded(tab, function() {
|
||||
is(
|
||||
tab.linkedBrowser.currentURI.spec,
|
||||
"about:mozilla",
|
||||
"restored tab has correct url"
|
||||
);
|
||||
// close and restore hidden tab
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
tab = ss.undoCloseTab(window, 0);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function whenTabIsLoaded(tab, callback) {
|
||||
tab.linkedBrowser.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
callback();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
// check that everything was restored correctly, clean up and finish
|
||||
await promiseBrowserLoaded(tab.linkedBrowser);
|
||||
is(
|
||||
tab.linkedBrowser.currentURI.spec,
|
||||
"about:mozilla",
|
||||
"restored tab has correct url"
|
||||
);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}
|
||||
|
@ -22,12 +22,16 @@ add_task(async function() {
|
||||
|
||||
// Change the "multiple" attribute of the <select> element and select some
|
||||
// options.
|
||||
await SpecialPowers.spawn(tab.linkedBrowser, [VALUES], values => {
|
||||
content.document.querySelector("select").multiple = true;
|
||||
for (let v of values) {
|
||||
content.document.querySelector(`option[value="${v}"]`).selected = true;
|
||||
}
|
||||
});
|
||||
await setPropertyOfFormField(tab.linkedBrowser, "select", "multiple", true);
|
||||
|
||||
for (let v of VALUES) {
|
||||
await setPropertyOfFormField(
|
||||
tab.linkedBrowser,
|
||||
`option[value="${v}"]`,
|
||||
"selected",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// Remove the tab.
|
||||
await promiseRemoveTabAndSessionState(tab);
|
||||
|
@ -36,11 +36,12 @@
|
||||
#include "mozilla/dom/MediaDevices.h"
|
||||
#include "mozilla/dom/PopupBlocker.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/UserActivationIPCUtils.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/WindowProxyHolder.h"
|
||||
@ -2277,44 +2278,6 @@ void BrowsingContext::IncrementHistoryEntryCountForBrowsingContext() {
|
||||
Unused << SetHistoryEntryCount(GetHistoryEntryCount() + 1);
|
||||
}
|
||||
|
||||
void BrowsingContext::FlushSessionStore() {
|
||||
nsTArray<RefPtr<BrowserChild>> nestedBrowserChilds;
|
||||
|
||||
PreOrderWalk([&](BrowsingContext* aContext) {
|
||||
BrowserChild* browserChild = BrowserChild::GetFrom(aContext->GetDocShell());
|
||||
if (browserChild && browserChild->GetBrowsingContext() == aContext) {
|
||||
nestedBrowserChilds.AppendElement(browserChild);
|
||||
}
|
||||
|
||||
if (aContext->CreatedDynamically()) {
|
||||
return WalkFlag::Skip;
|
||||
}
|
||||
|
||||
WindowContext* windowContext = aContext->GetCurrentWindowContext();
|
||||
if (!windowContext) {
|
||||
return WalkFlag::Skip;
|
||||
}
|
||||
|
||||
WindowGlobalChild* windowChild = windowContext->GetWindowGlobalChild();
|
||||
if (!windowChild) {
|
||||
return WalkFlag::Next;
|
||||
}
|
||||
|
||||
RefPtr<SessionStoreDataCollector> collector =
|
||||
windowChild->GetSessionStoreDataCollector();
|
||||
if (!collector) {
|
||||
return WalkFlag::Next;
|
||||
}
|
||||
|
||||
collector->Flush();
|
||||
return WalkFlag::Next;
|
||||
});
|
||||
|
||||
for (auto& child : nestedBrowserChilds) {
|
||||
child->UpdateSessionStore();
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<bool, bool> BrowsingContext::CanFocusCheck(CallerType aCallerType) {
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (!fm) {
|
||||
@ -2635,6 +2598,20 @@ nsresult BrowsingContext::ResetGVAutoplayRequestStatus() {
|
||||
return txn.Commit(this);
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_SessionStoreEpoch>,
|
||||
uint32_t aOldValue) {
|
||||
if (!mCurrentWindowContext) {
|
||||
return;
|
||||
}
|
||||
SessionStoreChild* sessionStoreChild =
|
||||
SessionStoreChild::From(mCurrentWindowContext->GetWindowGlobalChild());
|
||||
if (!sessionStoreChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStoreChild->SetEpoch(GetSessionStoreEpoch());
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_GVAudibleAutoplayRequestStatus>) {
|
||||
MOZ_ASSERT(IsTop(),
|
||||
"Should only set GVAudibleAutoplayRequestStatus in the top-level "
|
||||
@ -3407,6 +3384,17 @@ void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable* aRunner) {
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
bool BrowsingContext::IsDynamic() const {
|
||||
const BrowsingContext* current = this;
|
||||
do {
|
||||
if (current->CreatedDynamically()) {
|
||||
return true;
|
||||
}
|
||||
} while ((current = current->GetParent()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BrowsingContext::GetOffsetPath(nsTArray<uint32_t>& aPath) const {
|
||||
for (const BrowsingContext* current = this; current && current->GetParent();
|
||||
current = current->GetParent()) {
|
||||
|
@ -784,6 +784,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||
|
||||
bool CreatedDynamically() const { return mCreatedDynamically; }
|
||||
|
||||
// Returns true if this browsing context, or any ancestor to this browsing
|
||||
// context was created dynamically. See also `CreatedDynamically`.
|
||||
bool IsDynamic() const;
|
||||
|
||||
int32_t ChildOffset() const { return mChildOffset; }
|
||||
|
||||
bool GetOffsetPath(nsTArray<uint32_t>& aPath) const;
|
||||
@ -889,8 +893,6 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||
return GetPrefersColorSchemeOverride();
|
||||
}
|
||||
|
||||
void FlushSessionStore();
|
||||
|
||||
bool IsInBFCache() const;
|
||||
|
||||
bool AllowJavascript() const { return GetAllowJavascript(); }
|
||||
@ -1002,6 +1004,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||
return IsTop() && !aSource;
|
||||
}
|
||||
|
||||
void DidSet(FieldIndex<IDX_SessionStoreEpoch>, uint32_t aOldValue);
|
||||
|
||||
using CanSetResult = syncedcontext::CanSetResult;
|
||||
|
||||
// Ensure that opener is in the same BrowsingContextGroup.
|
||||
|
@ -2367,7 +2367,7 @@ void CanonicalBrowsingContext::UpdateSessionStoreSessionStorage(
|
||||
using DataPromise = BackgroundSessionStorageManager::DataPromise;
|
||||
BackgroundSessionStorageManager::GetData(
|
||||
this, StaticPrefs::browser_sessionstore_dom_storage_limit(),
|
||||
/* aCancelSessionStoreTiemr = */ true)
|
||||
/* aClearSessionStoreTimer = */ true)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[self = RefPtr{this}, aDone, epoch = GetSessionStoreEpoch()](
|
||||
const DataPromise::ResolveOrRejectValue& valueList) {
|
||||
|
@ -55,6 +55,8 @@ class MediaController;
|
||||
struct LoadingSessionHistoryInfo;
|
||||
class SSCacheCopy;
|
||||
class WindowGlobalParent;
|
||||
class SessionStoreFormData;
|
||||
class SessionStoreScrollData;
|
||||
|
||||
// CanonicalBrowsingContext is a BrowsingContext living in the parent
|
||||
// process, with whatever extra data that a BrowsingContext in the
|
||||
@ -524,6 +526,17 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||
|
||||
RefPtr<FeaturePolicy> mContainerFeaturePolicy;
|
||||
|
||||
friend class BrowserSessionStore;
|
||||
WeakPtr<SessionStoreFormData>& GetSessionStoreFormDataRef() {
|
||||
return mFormdata;
|
||||
}
|
||||
WeakPtr<SessionStoreScrollData>& GetSessionStoreScrollDataRef() {
|
||||
return mScroll;
|
||||
}
|
||||
|
||||
WeakPtr<SessionStoreFormData> mFormdata;
|
||||
WeakPtr<SessionStoreScrollData> mScroll;
|
||||
|
||||
RefPtr<RestoreState> mRestoreState;
|
||||
|
||||
// If this is a top level context, this is true if our browser ID is marked as
|
||||
|
@ -78,7 +78,7 @@
|
||||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
@ -5816,7 +5816,12 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
|
||||
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
if (IsForceReloadType(mLoadType)) {
|
||||
SessionStoreUtils::ResetSessionStore(mBrowsingContext);
|
||||
if (WindowContext* windowContext =
|
||||
mBrowsingContext->GetCurrentWindowContext()) {
|
||||
SessionStoreChild::From(windowContext->GetWindowGlobalChild())
|
||||
->SendResetSessionStore(
|
||||
mBrowsingContext, mBrowsingContext->GetSessionStoreEpoch());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6557,13 +6562,13 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
||||
return NS_OK;
|
||||
}
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
if (Document* document = GetDocument()) {
|
||||
if (WindowGlobalChild* windowChild = document->GetWindowGlobalChild()) {
|
||||
RefPtr<SessionStoreDataCollector> collector =
|
||||
SessionStoreDataCollector::CollectSessionStoreData(windowChild);
|
||||
collector->RecordInputChange();
|
||||
collector->RecordScrollChange();
|
||||
}
|
||||
if (WindowContext* windowContext =
|
||||
mBrowsingContext->GetCurrentWindowContext()) {
|
||||
// TODO(farre): File bug: From a user perspective this would probably be
|
||||
// just fine to run off the change listener timer. Turns out that a flush
|
||||
// is needed. Several tests depend on this behaviour. Could potentially be
|
||||
// an optimization for later. See Bug 1756995.
|
||||
SessionStoreChangeListener::FlushAllSessionStoreData(windowContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,15 +86,17 @@
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs_fission.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/ChromeMessageSender.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FrameCrashedEvent.h"
|
||||
#include "mozilla/dom/FrameLoaderBinding.h"
|
||||
#include "mozilla/dom/InProcessChild.h"
|
||||
#include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
|
||||
#include "mozilla/dom/PBrowser.h"
|
||||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreListener.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreParent.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/XULFrameElement.h"
|
||||
@ -164,8 +166,7 @@ using PrintPreviewResolver = std::function<void(const PrintPreviewResultInfo&)>;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFrameLoader, mPendingBrowsingContext,
|
||||
mMessageManager, mChildMessageManager,
|
||||
mRemoteBrowser,
|
||||
mSessionStoreChangeListener)
|
||||
mRemoteBrowser, mSessionStoreChild)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
|
||||
|
||||
@ -2041,14 +2042,9 @@ void nsFrameLoader::DestroyDocShell() {
|
||||
mChildMessageManager->FireUnloadEvent();
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->RemoveListeners();
|
||||
mSessionStoreListener = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->Stop();
|
||||
mSessionStoreChangeListener = nullptr;
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->Stop();
|
||||
mSessionStoreChild = nullptr;
|
||||
}
|
||||
|
||||
// Destroy the docshell.
|
||||
@ -2141,22 +2137,22 @@ void nsFrameLoader::SetOwnerContent(Element* aContent) {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mSessionStoreListener && mOwnerContent) {
|
||||
if (mSessionStoreChild && mOwnerContent) {
|
||||
// mOwnerContent will only be null when the frame loader is being destroyed,
|
||||
// so the session store listener will be destroyed along with it.
|
||||
// XXX(farre): This probably needs to update the cache. See bug 1698497.
|
||||
mSessionStoreListener->SetOwnerContent(mOwnerContent);
|
||||
mSessionStoreChild->SetOwnerContent(mOwnerContent);
|
||||
}
|
||||
|
||||
if (RefPtr<BrowsingContext> browsingContext = GetExtantBrowsingContext()) {
|
||||
browsingContext->SetEmbedderElement(mOwnerContent);
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
if (mSessionStoreChild) {
|
||||
// UpdateEventTargets will requery its browser contexts for event
|
||||
// targets, so this call needs to happen after the call to
|
||||
// SetEmbedderElement above.
|
||||
mSessionStoreChangeListener->UpdateEventTargets();
|
||||
mSessionStoreChild->UpdateEventTargets();
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
@ -3101,15 +3097,11 @@ nsresult nsFrameLoader::EnsureMessageManager() {
|
||||
GetDocShell(), mOwnerContent, mMessageManager);
|
||||
NS_ENSURE_TRUE(mChildMessageManager, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Set up a TabListener for sessionStore
|
||||
// Set up session store
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
mSessionStoreListener = new TabListener(GetDocShell(), mOwnerContent);
|
||||
rv = mSessionStoreListener->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSessionStoreChangeListener =
|
||||
SessionStoreChangeListener::Create(GetExtantBrowsingContext());
|
||||
if (XRE_IsParentProcess() && mIsTopLevelContent) {
|
||||
mSessionStoreChild = SessionStoreChild::GetOrCreate(
|
||||
GetExtantBrowsingContext(), mOwnerContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3237,6 +3229,21 @@ void nsFrameLoader::RequestUpdatePosition(ErrorResult& aRv) {
|
||||
}
|
||||
}
|
||||
|
||||
SessionStoreParent* nsFrameLoader::GetSessionStoreParent() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
if (mSessionStoreChild) {
|
||||
return static_cast<SessionStoreParent*>(
|
||||
InProcessChild::ParentActorFor(mSessionStoreChild));
|
||||
}
|
||||
|
||||
if (BrowserParent* browserParent = GetBrowserParent()) {
|
||||
return static_cast<SessionStoreParent*>(
|
||||
SingleManagedOrNull(browserParent->ManagedPSessionStoreParent()));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> nsFrameLoader::RequestTabStateFlush(
|
||||
ErrorResult& aRv) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
@ -3247,42 +3254,24 @@ already_AddRefed<Promise> nsFrameLoader::RequestTabStateFlush(
|
||||
}
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(ownerDoc->GetOwnerGlobal(), aRv);
|
||||
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> context = GetExtantBrowsingContext();
|
||||
if (!context) {
|
||||
BrowsingContext* browsingContext = GetExtantBrowsingContext();
|
||||
if (!browsingContext) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
context->FlushSessionStore();
|
||||
mSessionStoreListener->ForceFlushFromParent();
|
||||
context->Canonical()->UpdateSessionStoreSessionStorage(
|
||||
[promise]() { promise->MaybeResolveWithUndefined(); });
|
||||
|
||||
SessionStoreParent* sessionStoreParent = GetSessionStoreParent();
|
||||
if (!sessionStoreParent) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
using FlushPromise = ContentParent::FlushTabStatePromise;
|
||||
nsTArray<RefPtr<FlushPromise>> flushPromises;
|
||||
context->Group()->EachParent([&](ContentParent* aParent) {
|
||||
if (aParent->CanSend()) {
|
||||
flushPromises.AppendElement(aParent->SendFlushTabState(context));
|
||||
}
|
||||
});
|
||||
|
||||
RefPtr<FlushPromise::AllPromiseType> flushPromise =
|
||||
FlushPromise::All(GetCurrentSerialEventTarget(), flushPromises);
|
||||
|
||||
context->Canonical()->UpdateSessionStoreSessionStorage([flushPromise,
|
||||
promise]() {
|
||||
flushPromise->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[promise]() { promise->MaybeResolveWithUndefined(); });
|
||||
});
|
||||
sessionStoreParent->FlushAllSessionStoreChildren(
|
||||
[promise]() { promise->MaybeResolveWithUndefined(); });
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
@ -3297,10 +3286,8 @@ void nsFrameLoader::RequestFinalTabStateFlush() {
|
||||
RefPtr<WindowGlobalParent> wgp = canonical->GetCurrentWindowGlobal();
|
||||
RefPtr<Element> embedder = context->GetEmbedderElement();
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
context->FlushSessionStore();
|
||||
mSessionStoreListener->ForceFlushFromParent();
|
||||
|
||||
RefPtr<SessionStoreParent> sessionStoreParent = GetSessionStoreParent();
|
||||
if (!sessionStoreParent) {
|
||||
canonical->ClearPermanentKey();
|
||||
if (wgp) {
|
||||
wgp->NotifySessionStoreUpdatesComplete(embedder);
|
||||
@ -3309,24 +3296,15 @@ void nsFrameLoader::RequestFinalTabStateFlush() {
|
||||
return;
|
||||
}
|
||||
|
||||
using FlushPromise = ContentParent::FlushTabStatePromise;
|
||||
nsTArray<RefPtr<FlushPromise>> flushPromises;
|
||||
context->Group()->EachParent([&](ContentParent* aParent) {
|
||||
if (aParent->CanSend()) {
|
||||
flushPromises.AppendElement(aParent->SendFlushTabState(context));
|
||||
}
|
||||
});
|
||||
|
||||
FlushPromise::All(GetCurrentSerialEventTarget(), flushPromises)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[canonical = RefPtr{canonical}, wgp, embedder]() {
|
||||
if (canonical) {
|
||||
canonical->ClearPermanentKey();
|
||||
}
|
||||
if (wgp) {
|
||||
wgp->NotifySessionStoreUpdatesComplete(embedder);
|
||||
}
|
||||
});
|
||||
sessionStoreParent->FinalFlushAllSessionStoreChildren(
|
||||
[canonical, wgp, embedder]() {
|
||||
if (canonical) {
|
||||
canonical->ClearPermanentKey();
|
||||
}
|
||||
if (wgp) {
|
||||
wgp->NotifySessionStoreUpdatesComplete(embedder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void nsFrameLoader::RequestEpochUpdate(uint32_t aEpoch) {
|
||||
@ -3335,21 +3313,11 @@ void nsFrameLoader::RequestEpochUpdate(uint32_t aEpoch) {
|
||||
BrowsingContext* top = context->Top();
|
||||
Unused << top->SetSessionStoreEpoch(aEpoch);
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->SetEpoch(aEpoch);
|
||||
return;
|
||||
}
|
||||
|
||||
// If remote browsing (e10s), handle this with the BrowserParent.
|
||||
if (auto* browserParent = GetBrowserParent()) {
|
||||
Unused << browserParent->SendUpdateEpoch(aEpoch);
|
||||
}
|
||||
}
|
||||
|
||||
void nsFrameLoader::RequestSHistoryUpdate() {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->UpdateSHistoryChanges();
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->UpdateSHistoryChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,6 @@ class ChromeMessageSender;
|
||||
class ContentParent;
|
||||
class Document;
|
||||
class Element;
|
||||
class TabListener;
|
||||
class InProcessBrowserChildMessageManager;
|
||||
class MessageSender;
|
||||
class ProcessMessageManager;
|
||||
@ -73,7 +72,8 @@ class BrowserBridgeChild;
|
||||
class RemoteBrowser;
|
||||
struct RemotenessOptions;
|
||||
struct NavigationIsolationOptions;
|
||||
class SessionStoreChangeListener;
|
||||
class SessionStoreChild;
|
||||
class SessionStoreParent;
|
||||
|
||||
namespace ipc {
|
||||
class StructuredCloneData;
|
||||
@ -411,6 +411,12 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
||||
|
||||
void FireErrorEvent();
|
||||
|
||||
mozilla::dom::SessionStoreChild* GetSessionStoreChild() {
|
||||
return mSessionStoreChild;
|
||||
}
|
||||
|
||||
mozilla::dom::SessionStoreParent* GetSessionStoreParent();
|
||||
|
||||
private:
|
||||
nsFrameLoader(mozilla::dom::Element* aOwner,
|
||||
mozilla::dom::BrowsingContext* aBrowsingContext, bool aIsRemote,
|
||||
@ -520,9 +526,10 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
||||
// Holds the last known size of the frame.
|
||||
mozilla::ScreenIntSize mLazySize;
|
||||
|
||||
RefPtr<mozilla::dom::TabListener> mSessionStoreListener;
|
||||
|
||||
RefPtr<mozilla::dom::SessionStoreChangeListener> mSessionStoreChangeListener;
|
||||
// Actor for collecting session store data from content children. This will be
|
||||
// cleared and set to null eagerly when taking down the frameloader to break
|
||||
// refcounted cycles early.
|
||||
RefPtr<mozilla::dom::SessionStoreChild> mSessionStoreChild;
|
||||
|
||||
nsCString mRemoteType;
|
||||
|
||||
|
47
dom/chrome-webidl/BrowserSessionStore.webidl
Normal file
47
dom/chrome-webidl/BrowserSessionStore.webidl
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
// object contains either a CollectedFileListValue or a CollectedNonMultipleSelectValue or Sequence<DOMString>
|
||||
typedef (DOMString or boolean or object) FormDataValue;
|
||||
|
||||
[ChromeOnly, Exposed=Window]
|
||||
interface SessionStoreFormData {
|
||||
[Cached, Pure]
|
||||
readonly attribute ByteString? url;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute record<DOMString, FormDataValue>? id;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute record<DOMString, FormDataValue>? xpath;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute DOMString? innerHTML;
|
||||
|
||||
[Cached, Frozen, Pure]
|
||||
readonly attribute sequence<SessionStoreFormData?>? children;
|
||||
|
||||
object toJSON();
|
||||
};
|
||||
|
||||
[ChromeOnly, Exposed=Window]
|
||||
interface SessionStoreScrollData {
|
||||
[Cached, Pure]
|
||||
readonly attribute ByteString? scroll;
|
||||
|
||||
[Cached, Pure]
|
||||
readonly attribute sequence<SessionStoreScrollData?>? children;
|
||||
|
||||
object toJSON();
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary UpdateSessionStoreData {
|
||||
// This is docshell caps, but on-disk format uses the disallow property name.
|
||||
ByteString? disallow;
|
||||
boolean isPrivate;
|
||||
SessionStoreFormData? formdata;
|
||||
SessionStoreScrollData? scroll;
|
||||
};
|
@ -167,28 +167,3 @@ dictionary InputElementData {
|
||||
sequence<DOMString> strVal;
|
||||
sequence<boolean> boolVal;
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary UpdateSessionStoreData {
|
||||
ByteString docShellCaps;
|
||||
boolean isPrivate;
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary SessionStoreWindowStateChange {
|
||||
SessionStoreFormData formdata;
|
||||
SessionStoreScroll scroll;
|
||||
boolean hasChildren;
|
||||
required sequence<unsigned long> path;
|
||||
};
|
||||
|
||||
dictionary SessionStoreFormData {
|
||||
ByteString url;
|
||||
record<DOMString, CollectedFormDataValue> id;
|
||||
record<DOMString, CollectedFormDataValue> xpath;
|
||||
DOMString innerHTML;
|
||||
};
|
||||
|
||||
dictionary SessionStoreScroll {
|
||||
ByteString scroll;
|
||||
};
|
||||
|
@ -37,6 +37,7 @@ PREPROCESSED_WEBIDL_FILES = [
|
||||
]
|
||||
|
||||
WEBIDL_FILES = [
|
||||
"BrowserSessionStore.webidl",
|
||||
"BrowsingContext.webidl",
|
||||
"ChannelWrapper.webidl",
|
||||
"ClonedErrorHolder.webidl",
|
||||
|
@ -69,10 +69,8 @@
|
||||
#include "mozilla/dom/PBrowser.h"
|
||||
#include "mozilla/dom/PaymentRequestChild.h"
|
||||
#include "mozilla/dom/PointerEventHandler.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/SessionStoreListener.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/WindowProxyHolder.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
@ -522,12 +520,7 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
|
||||
mIPCOpen = true;
|
||||
|
||||
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
|
||||
mSessionStoreListener = new TabListener(docShell, nullptr);
|
||||
rv = mSessionStoreListener->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSessionStoreChangeListener =
|
||||
SessionStoreChangeListener::Create(mBrowsingContext);
|
||||
mSessionStoreChild = SessionStoreChild::GetOrCreate(mBrowsingContext);
|
||||
}
|
||||
|
||||
// We've all set up, make sure our visibility state is consistent. This is
|
||||
@ -545,8 +538,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowserChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusFilter)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStoreChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -555,8 +547,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowserChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusFilter)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStoreChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowserChild)
|
||||
@ -849,14 +840,9 @@ void BrowserChild::DestroyWindow() {
|
||||
mCoalescedTouchMoveEventFlusher = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->RemoveListeners();
|
||||
mSessionStoreListener = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->Stop();
|
||||
mSessionStoreChangeListener = nullptr;
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->Stop();
|
||||
mSessionStoreChild = nullptr;
|
||||
}
|
||||
|
||||
// In case we don't have chance to process all entries, clean all data in
|
||||
@ -2060,16 +2046,9 @@ mozilla::ipc::IPCResult BrowserChild::RecvNativeSynthesisResponse(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvUpdateEpoch(const uint32_t& aEpoch) {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->SetEpoch(aEpoch);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvUpdateSHistory() {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->UpdateSHistoryChanges();
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->UpdateSHistoryChanges();
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -3809,26 +3788,10 @@ nsresult BrowserChild::PrepareProgressListenerData(
|
||||
return PrepareRequestData(aRequest, aRequestData);
|
||||
}
|
||||
|
||||
bool BrowserChild::UpdateSessionStore() {
|
||||
if (!mSessionStoreListener) {
|
||||
return false;
|
||||
void BrowserChild::UpdateSessionStore() {
|
||||
if (mSessionStoreChild) {
|
||||
mSessionStoreChild->UpdateSessionStore();
|
||||
}
|
||||
RefPtr<ContentSessionStore> store = mSessionStoreListener->GetSessionStore();
|
||||
|
||||
Maybe<nsCString> docShellCaps;
|
||||
if (store->IsDocCapChanged()) {
|
||||
docShellCaps.emplace(store->GetDocShellCaps());
|
||||
}
|
||||
|
||||
Maybe<bool> privatedMode;
|
||||
if (store->IsPrivateChanged()) {
|
||||
privatedMode.emplace(store->GetPrivateModeEnabled());
|
||||
}
|
||||
|
||||
Unused << SendSessionStoreUpdate(docShellCaps, privatedMode,
|
||||
store->GetAndClearSHistoryChanged(),
|
||||
mSessionStoreListener->GetEpoch());
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -86,9 +86,7 @@ class TabGroup;
|
||||
class ClonedMessageData;
|
||||
class CoalescedMouseData;
|
||||
class CoalescedWheelData;
|
||||
class ContentSessionStore;
|
||||
class SessionStoreChangeListener;
|
||||
class TabListener;
|
||||
class SessionStoreChild;
|
||||
class RequestData;
|
||||
class WebProgressData;
|
||||
|
||||
@ -396,8 +394,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
||||
aApzResponse);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateEpoch(const uint32_t& aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSHistory();
|
||||
|
||||
mozilla::ipc::IPCResult RecvNativeSynthesisResponse(
|
||||
@ -673,7 +669,11 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
||||
mCancelContentJSEpoch = aEpoch;
|
||||
}
|
||||
|
||||
bool UpdateSessionStore();
|
||||
void UpdateSessionStore();
|
||||
|
||||
mozilla::dom::SessionStoreChild* GetSessionStoreChild() {
|
||||
return mSessionStoreChild;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Check if the window this BrowserChild is associated with supports
|
||||
@ -892,8 +892,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
||||
RefPtr<CoalescedTouchMoveFlusher> mCoalescedTouchMoveEventFlusher;
|
||||
|
||||
RefPtr<layers::IAPZCTreeManager> mApzcTreeManager;
|
||||
RefPtr<TabListener> mSessionStoreListener;
|
||||
RefPtr<SessionStoreChangeListener> mSessionStoreChangeListener;
|
||||
RefPtr<SessionStoreChild> mSessionStoreChild;
|
||||
|
||||
// The most recently seen layer observer epoch in RecvSetDocShellIsActive.
|
||||
layers::LayersObserverEpoch mLayersObserverEpoch;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#endif
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/dom/BrowserHost.h"
|
||||
#include "mozilla/dom/BrowserSessionStore.h"
|
||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||
#include "mozilla/dom/CancelContentJSOptionsBinding.h"
|
||||
#include "mozilla/dom/ChromeMessageSender.h"
|
||||
@ -32,8 +33,7 @@
|
||||
#include "mozilla/dom/RemoteDragStartData.h"
|
||||
#include "mozilla/dom/RemoteWebProgressRequest.h"
|
||||
#include "mozilla/dom/SessionHistoryEntry.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||
#include "mozilla/dom/SessionStoreParent.h"
|
||||
#include "mozilla/dom/UserActivation.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
@ -53,6 +53,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ProcessHangMonitor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticPrefs_accessibility.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
@ -128,7 +129,6 @@
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/ProfilerLabels.h"
|
||||
#include "MMPrinter.h"
|
||||
#include "SessionStoreFunctions.h"
|
||||
#include "mozilla/dom/CrashReport.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
@ -1372,6 +1372,17 @@ IPCResult BrowserParent::RecvIndexedDBPermissionRequest(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<PSessionStoreParent>
|
||||
BrowserParent::AllocPSessionStoreParent() {
|
||||
RefPtr<BrowserSessionStore> sessionStore =
|
||||
BrowserSessionStore::GetOrCreate(mBrowsingContext->Top());
|
||||
if (!sessionStore) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return do_AddRef(new SessionStoreParent(mBrowsingContext, sessionStore));
|
||||
}
|
||||
|
||||
IPCResult BrowserParent::RecvNewWindowGlobal(
|
||||
ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
|
||||
const WindowGlobalInit& aInit) {
|
||||
@ -3008,41 +3019,6 @@ BrowserParent::BrowsingContextForWebProgress(
|
||||
return browsingContext.forget();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
|
||||
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
|
||||
const bool aNeedCollectSHistory, const uint32_t& aEpoch) {
|
||||
UpdateSessionStoreData data;
|
||||
if (aDocShellCaps.isSome()) {
|
||||
data.mDocShellCaps.Construct() = aDocShellCaps.value();
|
||||
}
|
||||
if (aPrivatedMode.isSome()) {
|
||||
data.mIsPrivate.Construct() = aPrivatedMode.value();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
NS_ENSURE_TRUE(wrapped, IPC_OK());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), data, &update)) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(),
|
||||
mBrowsingContext->Canonical()->Top()->PermanentKey());
|
||||
|
||||
Unused << funcs->UpdateSessionStore(mFrameElement, mBrowsingContext, key,
|
||||
aEpoch, aNeedCollectSHistory, update);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvIntrinsicSizeOrRatioChanged(
|
||||
const Maybe<IntrinsicSize>& aIntrinsicSize,
|
||||
const Maybe<AspectRatio>& aIntrinsicRatio) {
|
||||
|
@ -317,10 +317,6 @@ class BrowserParent final : public PBrowserParent,
|
||||
already_AddRefed<CanonicalBrowsingContext> BrowsingContextForWebProgress(
|
||||
const WebProgressData& aWebProgressData);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
|
||||
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
|
||||
const bool aNeedCollectSHistory, const uint32_t& aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvIntrinsicSizeOrRatioChanged(
|
||||
const Maybe<IntrinsicSize>& aIntrinsicSize,
|
||||
const Maybe<AspectRatio>& aIntrinsicRatio);
|
||||
@ -445,6 +441,8 @@ class BrowserParent final : public PBrowserParent,
|
||||
const IAccessibleHolder& aDocCOMProxy) override;
|
||||
#endif
|
||||
|
||||
already_AddRefed<PSessionStoreParent> AllocPSessionStoreParent();
|
||||
|
||||
mozilla::ipc::IPCResult RecvNewWindowGlobal(
|
||||
ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
|
||||
const WindowGlobalInit& aInit);
|
||||
|
@ -4524,25 +4524,6 @@ mozilla::ipc::IPCResult ContentChild::RecvInitNextGenLocalStorageEnabled(
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvFlushTabState(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
FlushTabStateResolver&& aResolver) {
|
||||
if (aContext.IsNullOrDiscarded()) {
|
||||
aResolver(false);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (auto* docShell = nsDocShell::Cast(aContext->GetDocShell())) {
|
||||
docShell->CollectWireframe();
|
||||
}
|
||||
|
||||
aContext->FlushSessionStore();
|
||||
|
||||
aResolver(true);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvGoBack(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
const Maybe<int32_t>& aCancelContentJSEpoch, bool aRequireUserInteraction,
|
||||
|
@ -812,10 +812,6 @@ class ContentChild final : public PContentChild,
|
||||
const MaybeDiscarded<BrowsingContext>& aStartingAt,
|
||||
DispatchBeforeUnloadToSubtreeResolver&& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvFlushTabState(
|
||||
const MaybeDiscarded<BrowsingContext>& aContext,
|
||||
FlushTabStateResolver&& aResolver);
|
||||
|
||||
mozilla::ipc::IPCResult RecvDecoderSupportedMimeTypes(
|
||||
nsTArray<nsCString>&& aSupportedTypes);
|
||||
|
||||
|
@ -17,6 +17,7 @@ include protocol PParentToChildStream;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PRemoteLazyInputStream;
|
||||
include protocol PPaymentRequest;
|
||||
include protocol PSessionStore;
|
||||
include protocol PWindowGlobal;
|
||||
include protocol PBrowserBridge;
|
||||
include protocol PVsync;
|
||||
@ -190,6 +191,7 @@ struct PrintPreviewResultInfo
|
||||
|
||||
manages PFilePicker;
|
||||
manages PPaymentRequest;
|
||||
manages PSessionStore;
|
||||
manages PWindowGlobal;
|
||||
manages PBrowserBridge;
|
||||
manages PVsync;
|
||||
@ -575,9 +577,6 @@ parent:
|
||||
|
||||
async NavigationFinished();
|
||||
|
||||
async SessionStoreUpdate(nsCString? aDocShellCaps, bool? aPrivatedMode,
|
||||
bool aNeedCollectSHistory, uint32_t aEpoch);
|
||||
|
||||
async IntrinsicSizeOrRatioChanged(IntrinsicSize? aIntrinsicSize,
|
||||
AspectRatio? aIntrinsicRatio);
|
||||
|
||||
@ -595,7 +594,6 @@ parent:
|
||||
|
||||
child:
|
||||
async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
|
||||
async UpdateEpoch(uint32_t aEpoch);
|
||||
async UpdateSHistory();
|
||||
async CloneDocumentTreeIntoSelf(MaybeDiscardedBrowsingContext aBc, PrintData aPrintData) returns(bool aSuccess);
|
||||
async UpdateRemotePrintSettings(PrintData aPrintData);
|
||||
@ -1016,6 +1014,9 @@ parent:
|
||||
/** Fetches the visited status for an array of URIs (Android-only). */
|
||||
async QueryVisitedState(nsIURI[] aURIs);
|
||||
|
||||
/** Create a session store for a browser child. */
|
||||
async PSessionStore();
|
||||
|
||||
/**
|
||||
* Construct a new WindowGlobal for an existing global in the content process
|
||||
*/
|
||||
|
@ -1027,9 +1027,6 @@ child:
|
||||
// Update the cached list of codec supported in the given process.
|
||||
async UpdateMediaCodecsSupported(RemoteDecodeIn aLocation, MediaCodecsSupported aSupported);
|
||||
|
||||
async FlushTabState(MaybeDiscardedBrowsingContext aBrowsingContext)
|
||||
returns(bool aHadContext);
|
||||
|
||||
// Send the list of the supported mimetypes in the given process. GeckoView-specific
|
||||
async DecoderSupportedMimeTypes(nsCString[] supportedTypes);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PExtensions;
|
||||
include protocol PSessionStore;
|
||||
include protocol PWindowGlobal;
|
||||
|
||||
include DOMTypes;
|
||||
@ -23,6 +24,7 @@ namespace dom {
|
||||
async protocol PInProcess
|
||||
{
|
||||
manages PExtensions;
|
||||
manages PSessionStore;
|
||||
manages PWindowGlobal;
|
||||
};
|
||||
|
||||
|
@ -180,11 +180,6 @@ parent:
|
||||
|
||||
async RequestRestoreTabContent();
|
||||
|
||||
async UpdateSessionStore(FormData? aFormData, nsPoint? aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
async ResetSessionStore(uint32_t aEpoch);
|
||||
|
||||
// Add the flags in aOnFlags to the current BFCache status and remove the
|
||||
// flags in aOffFlags from the current BFCache status. See the BFCacheStatus
|
||||
// enum for the valid flags.
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
|
||||
#include "mozilla/dom/SessionStoreRestoreData.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/WindowGlobalActorsBinding.h"
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/dom/InProcessChild.h"
|
||||
@ -327,11 +326,6 @@ void WindowGlobalChild::Destroy() {
|
||||
if (!browserChild || !browserChild->IsDestroyed()) {
|
||||
SendDestroy();
|
||||
}
|
||||
|
||||
if (mSessionStoreDataCollector) {
|
||||
mSessionStoreDataCollector->Cancel();
|
||||
mSessionStoreDataCollector = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalChild::RecvMakeFrameLocal(
|
||||
@ -703,20 +697,9 @@ nsISupports* WindowGlobalChild::GetParentObject() {
|
||||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
|
||||
void WindowGlobalChild::SetSessionStoreDataCollector(
|
||||
SessionStoreDataCollector* aCollector) {
|
||||
mSessionStoreDataCollector = aCollector;
|
||||
}
|
||||
|
||||
SessionStoreDataCollector* WindowGlobalChild::GetSessionStoreDataCollector()
|
||||
const {
|
||||
return mSessionStoreDataCollector;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WEAK_PTR(WindowGlobalChild, mWindowGlobal,
|
||||
mContainerFeaturePolicy,
|
||||
mWindowContext,
|
||||
mSessionStoreDataCollector)
|
||||
mWindowContext)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalChild)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
@ -28,7 +28,6 @@ class WindowGlobalParent;
|
||||
class JSWindowActorChild;
|
||||
class JSActorMessageMeta;
|
||||
class BrowserChild;
|
||||
class SessionStoreDataCollector;
|
||||
|
||||
/**
|
||||
* Actor for a single nsGlobalWindowInner. This actor is used to communicate
|
||||
@ -133,9 +132,6 @@ class WindowGlobalChild final : public WindowGlobalActor,
|
||||
return mContainerFeaturePolicy;
|
||||
}
|
||||
|
||||
void SetSessionStoreDataCollector(SessionStoreDataCollector* aCollector);
|
||||
SessionStoreDataCollector* GetSessionStoreDataCollector() const;
|
||||
|
||||
void UnblockBFCacheFor(BFCacheStatus aStatus);
|
||||
void BlockBFCacheFor(BFCacheStatus aStatus);
|
||||
|
||||
@ -205,7 +201,6 @@ class WindowGlobalChild final : public WindowGlobalActor,
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
RefPtr<dom::FeaturePolicy> mContainerFeaturePolicy;
|
||||
nsCOMPtr<nsIURI> mDocumentURI;
|
||||
RefPtr<SessionStoreDataCollector> mSessionStoreDataCollector;
|
||||
int64_t mBeforeUnloadListeners = 0;
|
||||
};
|
||||
|
||||
|
@ -26,9 +26,6 @@
|
||||
#include "mozilla/dom/ChromeUtils.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/ServoCSSParser.h"
|
||||
@ -535,16 +532,6 @@ const nsACString& WindowGlobalParent::GetRemoteType() {
|
||||
return NOT_REMOTE_TYPE;
|
||||
}
|
||||
|
||||
static nsCString PointToString(const nsPoint& aPoint) {
|
||||
int scrollX = nsPresContext::AppUnitsToIntCSSPixels(aPoint.x);
|
||||
int scrollY = nsPresContext::AppUnitsToIntCSSPixels(aPoint.y);
|
||||
if ((scrollX != 0) || (scrollY != 0)) {
|
||||
return nsPrintfCString("%d,%d", scrollX, scrollY);
|
||||
}
|
||||
|
||||
return ""_ns;
|
||||
}
|
||||
|
||||
void WindowGlobalParent::NotifyContentBlockingEvent(
|
||||
uint32_t aEvent, nsIRequest* aRequest, bool aBlocked,
|
||||
const nsACString& aTrackingOrigin,
|
||||
@ -1166,44 +1153,6 @@ void WindowGlobalParent::FinishAccumulatingPageUseCounters() {
|
||||
mPageUseCounters = nullptr;
|
||||
}
|
||||
|
||||
static void GetFormData(JSContext* aCx, const sessionstore::FormData& aFormData,
|
||||
nsIURI* aDocumentURI, SessionStoreFormData& aUpdate) {
|
||||
if (!aFormData.hasData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool parseSessionData = false;
|
||||
if (aDocumentURI) {
|
||||
nsCString& url = aUpdate.mUrl.Construct();
|
||||
aDocumentURI->GetSpecIgnoringRef(url);
|
||||
// We want to avoid saving data for about:sessionrestore as a string.
|
||||
// Since it's stored in the form as stringified JSON, stringifying
|
||||
// further causes an explosion of escape characters. cf. bug 467409
|
||||
parseSessionData =
|
||||
url == "about:sessionrestore"_ns || url == "about:welcomeback"_ns;
|
||||
}
|
||||
|
||||
if (!aFormData.innerHTML().IsEmpty()) {
|
||||
aUpdate.mInnerHTML.Construct(aFormData.innerHTML());
|
||||
}
|
||||
|
||||
if (!aFormData.id().IsEmpty()) {
|
||||
auto& id = aUpdate.mId.Construct();
|
||||
if (NS_FAILED(SessionStoreUtils::ConstructFormDataValues(
|
||||
aCx, aFormData.id(), id.Entries(), parseSessionData))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aFormData.xpath().IsEmpty()) {
|
||||
auto& xpath = aUpdate.mXpath.Construct();
|
||||
if (NS_FAILED(SessionStoreUtils::ConstructFormDataValues(
|
||||
aCx, aFormData.xpath(), xpath.Entries()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Element* WindowGlobalParent::GetRootOwnerElement() {
|
||||
WindowGlobalParent* top = TopWindowContext();
|
||||
if (!top) {
|
||||
@ -1221,104 +1170,6 @@ Element* WindowGlobalParent::GetRootOwnerElement() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult WindowGlobalParent::WriteFormDataAndScrollToSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch) {
|
||||
if (!aFormData && !aScrollPosition) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> context = BrowsingContext();
|
||||
if (!context) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
if (!funcs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RootedDictionary<SessionStoreWindowStateChange> windowState(jsapi.cx());
|
||||
|
||||
if (aFormData) {
|
||||
GetFormData(jsapi.cx(), *aFormData, mDocumentURI,
|
||||
windowState.mFormdata.Construct());
|
||||
}
|
||||
|
||||
if (aScrollPosition) {
|
||||
auto& update = windowState.mScroll.Construct();
|
||||
if (*aScrollPosition != nsPoint(0, 0)) {
|
||||
update.mScroll.Construct() = PointToString(*aScrollPosition);
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<uint32_t> path;
|
||||
if (!context->GetOffsetPath(path)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
windowState.mPath = std::move(path);
|
||||
windowState.mHasChildren.Construct() = !context->Children().IsEmpty();
|
||||
|
||||
JS::RootedValue update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), windowState, &update)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(), context->Top()->PermanentKey());
|
||||
|
||||
return funcs->UpdateSessionStoreForWindow(GetRootOwnerElement(), context, key,
|
||||
aEpoch, update);
|
||||
}
|
||||
|
||||
nsresult WindowGlobalParent::ResetSessionStore(uint32_t aEpoch) {
|
||||
RefPtr<CanonicalBrowsingContext> context = BrowsingContext();
|
||||
if (!context) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
if (!funcs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RootedDictionary<SessionStoreWindowStateChange> windowState(jsapi.cx());
|
||||
|
||||
nsTArray<uint32_t> path;
|
||||
if (!context->GetOffsetPath(path)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
windowState.mPath = std::move(path);
|
||||
windowState.mHasChildren.Construct() = false;
|
||||
windowState.mFormdata.Construct();
|
||||
windowState.mScroll.Construct();
|
||||
|
||||
JS::RootedValue update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), windowState, &update)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(), context->Top()->PermanentKey());
|
||||
|
||||
return funcs->UpdateSessionStoreForWindow(GetRootOwnerElement(), context, key,
|
||||
aEpoch, update);
|
||||
}
|
||||
|
||||
void WindowGlobalParent::NotifySessionStoreUpdatesComplete(Element* aEmbedder) {
|
||||
if (!aEmbedder) {
|
||||
aEmbedder = GetRootOwnerElement();
|
||||
@ -1331,27 +1182,6 @@ void WindowGlobalParent::NotifySessionStoreUpdatesComplete(Element* aEmbedder) {
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvUpdateSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch) {
|
||||
if (NS_FAILED(WriteFormDataAndScrollToSessionStore(aFormData, aScrollPosition,
|
||||
aEpoch))) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Failed to update session store entry."));
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvResetSessionStore(
|
||||
uint32_t aEpoch) {
|
||||
if (NS_FAILED(ResetSessionStore(aEpoch))) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ParentIPC: Failed to reset session store entry."));
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WindowGlobalParent::RecvRequestRestoreTabContent() {
|
||||
CanonicalBrowsingContext* bc = BrowsingContext();
|
||||
if (bc && bc->AncestorsAreCurrent()) {
|
||||
|
@ -80,7 +80,7 @@ class WindowGlobalParent final : public WindowContext,
|
||||
WindowGlobalParent* TopWindowContext() {
|
||||
return static_cast<WindowGlobalParent*>(WindowContext::TopWindowContext());
|
||||
}
|
||||
CanonicalBrowsingContext* GetBrowsingContext() {
|
||||
CanonicalBrowsingContext* GetBrowsingContext() const {
|
||||
return CanonicalBrowsingContext::Cast(WindowContext::GetBrowsingContext());
|
||||
}
|
||||
|
||||
@ -214,10 +214,6 @@ class WindowGlobalParent final : public WindowContext,
|
||||
|
||||
const nsACString& GetRemoteType() override;
|
||||
|
||||
nsresult WriteFormDataAndScrollToSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
void NotifySessionStoreUpdatesComplete(Element* aEmbedder);
|
||||
|
||||
Maybe<uint64_t> GetSingleChannelId() { return mSingleChannelId; }
|
||||
@ -288,12 +284,6 @@ class WindowGlobalParent final : public WindowContext,
|
||||
|
||||
mozilla::ipc::IPCResult RecvRequestRestoreTabContent();
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateSessionStore(
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvResetSessionStore(uint32_t aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateBFCacheStatus(const uint32_t& aOnFlags,
|
||||
const uint32_t& aOffFlags);
|
||||
|
||||
@ -320,8 +310,6 @@ class WindowGlobalParent final : public WindowContext,
|
||||
bool ShouldTrackSiteOriginTelemetry();
|
||||
void FinishAccumulatingPageUseCounters();
|
||||
|
||||
nsresult ResetSessionStore(uint32_t aEpoch);
|
||||
|
||||
// Returns failure if the new storage principal cannot be validated
|
||||
// against the current document principle.
|
||||
nsresult SetDocumentStoragePrincipal(
|
||||
|
293
toolkit/components/sessionstore/BrowserSessionStore.cpp
Normal file
293
toolkit/components/sessionstore/BrowserSessionStore.cpp
Normal file
@ -0,0 +1,293 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/dom/BrowserSessionStore.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
#include "mozilla/dom/BrowserSessionStoreBinding.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/SessionStoreFormData.h"
|
||||
#include "mozilla/dom/SessionStoreScrollData.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsHashtablesFwd.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static StaticAutoPtr<nsTHashMap<nsUint64HashKey, BrowserSessionStore*>>
|
||||
sSessionStore;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(BrowserSessionStore, mBrowsingContext, mFormData,
|
||||
mScrollData)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowserSessionStore, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowserSessionStore, Release)
|
||||
|
||||
/* static */
|
||||
already_AddRefed<BrowserSessionStore> BrowserSessionStore::GetOrCreate(
|
||||
CanonicalBrowsingContext* aBrowsingContext) {
|
||||
if (!aBrowsingContext->IsTop()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!sSessionStore) {
|
||||
sSessionStore = new nsTHashMap<nsUint64HashKey, BrowserSessionStore*>();
|
||||
ClearOnShutdown(&sSessionStore);
|
||||
}
|
||||
|
||||
return do_AddRef(sSessionStore->LookupOrInsertWith(
|
||||
aBrowsingContext->Id(),
|
||||
[&] { return new BrowserSessionStore(aBrowsingContext); }));
|
||||
}
|
||||
|
||||
BrowserSessionStore::BrowserSessionStore(
|
||||
CanonicalBrowsingContext* aBrowsingContext)
|
||||
: mBrowsingContext(aBrowsingContext) {}
|
||||
|
||||
SessionStoreFormData* BrowserSessionStore::GetFormdata() { return mFormData; }
|
||||
|
||||
SessionStoreScrollData* BrowserSessionStore::GetScroll() { return mScrollData; }
|
||||
|
||||
static bool ShouldUpdateSessionStore(CanonicalBrowsingContext* aBrowsingContext,
|
||||
uint32_t aEpoch) {
|
||||
if (!aBrowsingContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aBrowsingContext->Top()->GetSessionStoreEpoch() != aEpoch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aBrowsingContext->IsReplaced()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aBrowsingContext->IsDynamic()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// With GetOrCreate we can create either of the weak fields:
|
||||
// WeakPtr<SessionStoreFormData> mFormdata;
|
||||
// WeakPtr<SessionStoreScrollData> mScroll;
|
||||
// in CanonicalBrowsingContext. If one already exists, then we return that.
|
||||
template <typename T, WeakPtr<T>& (CanonicalBrowsingContext::*GetWeakRef)()>
|
||||
static already_AddRefed<T> GetOrCreateEntry(
|
||||
CanonicalBrowsingContext* aBrowsingContext) {
|
||||
typename T::LocationType& location = (aBrowsingContext->*GetWeakRef)();
|
||||
RefPtr<T> entry = location.get();
|
||||
if (!entry) {
|
||||
entry = MakeRefPtr<T>();
|
||||
location = entry;
|
||||
}
|
||||
|
||||
return entry.forget();
|
||||
}
|
||||
|
||||
// With InsertEntry we can insert an entry in the session store data tree in
|
||||
// either of the weak fields:
|
||||
// WeakPtr<SessionStoreFormData> mFormdata;
|
||||
// WeakPtr<SessionStoreScrollData> mScroll;
|
||||
// in CanonicalBrowsingContext. If an entry is inserted where there is no parent
|
||||
// entry, a spine of entries will be created until one is found, or we reach the
|
||||
// top browsing context.
|
||||
template <typename T>
|
||||
void InsertEntry(BrowsingContext* aBrowsingContext, T* aParent, T* aUpdate) {
|
||||
int32_t offset = aBrowsingContext->ChildOffset();
|
||||
if (offset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
aParent->ClearCachedChildren();
|
||||
|
||||
auto& children = aParent->Children();
|
||||
|
||||
children.EnsureLengthAtLeast(offset + 1);
|
||||
if (children[offset] && !aBrowsingContext->Children().IsEmpty()) {
|
||||
children[offset]->ClearCachedChildren();
|
||||
aUpdate->ClearCachedChildren();
|
||||
}
|
||||
|
||||
children[offset] = aUpdate;
|
||||
}
|
||||
|
||||
// With RemoveEntry we can remove an entry in the session store data tree in
|
||||
// either of the weak fields:
|
||||
// WeakPtr<SessionStoreFormData> mFormdata;
|
||||
// WeakPtr<SessionStoreScrollData> mScroll;
|
||||
// in CanonicalBrowsingContext. If an entry is removed, where its parent doesn't
|
||||
// contain data, we'll remove the parent and repeat until we either find an
|
||||
// entry with data or reach the top browsing context.
|
||||
template <typename T>
|
||||
void RemoveEntry(BrowsingContext* aBrowsingContext, T* aParent) {
|
||||
int32_t offset = aBrowsingContext->ChildOffset();
|
||||
if (offset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
aParent->ClearCachedChildren();
|
||||
|
||||
auto& children = aParent->Children();
|
||||
size_t length = children.Length();
|
||||
if (children.Length() <= static_cast<size_t>(offset)) {
|
||||
// The children array doesn't extend to offset.
|
||||
return;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(offset) < length - 1) {
|
||||
// offset is before the last item in the children array.
|
||||
children[offset] = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// offset is the last item, find the first non-null item before it
|
||||
// and remove anything after that item.
|
||||
while (offset > 0 && !children[offset - 1]) {
|
||||
--offset;
|
||||
}
|
||||
|
||||
children.TruncateLength(offset);
|
||||
}
|
||||
|
||||
// With UpdateSessionStoreField we can update an entry in the session store
|
||||
// data tree in either of the weak fields:
|
||||
// WeakPtr<SessionStoreFormData> mFormdata;
|
||||
// WeakPtr<SessionStoreScrollData> mScroll;
|
||||
// in CanonicalBrowsingContext. UpdateSessionStoreField uses the above
|
||||
// functions, `GetOrCreateEntry`, `InsertEntry` and `RemoveEntry` to operate on
|
||||
// the weak fields. We return the top-level entry attached to the top browsing
|
||||
// context through `aEntry`. If the entire browsing context tree contains no
|
||||
// session store data this will be set to nullptr.
|
||||
template <typename T, WeakPtr<T>& (CanonicalBrowsingContext::*GetWeakRef)()>
|
||||
void UpdateSessionStoreField(CanonicalBrowsingContext* aBrowsingContext,
|
||||
const typename T::CollectedType& aUpdate,
|
||||
T** aEntry) {
|
||||
RefPtr<T> currentEntry;
|
||||
|
||||
if (T::HasData(aUpdate)) {
|
||||
currentEntry = GetOrCreateEntry<T, GetWeakRef>(aBrowsingContext);
|
||||
currentEntry->Update(aUpdate);
|
||||
|
||||
CanonicalBrowsingContext* currentBrowsingContext = aBrowsingContext;
|
||||
while (CanonicalBrowsingContext* parent =
|
||||
currentBrowsingContext->GetParent()) {
|
||||
WeakPtr<T>& parentEntry = (parent->*GetWeakRef)();
|
||||
if (parentEntry) {
|
||||
InsertEntry(aBrowsingContext, parentEntry.get(), currentEntry.get());
|
||||
break;
|
||||
}
|
||||
|
||||
RefPtr<T> entry = GetOrCreateEntry<T, GetWeakRef>(parent);
|
||||
InsertEntry(currentBrowsingContext, entry.get(), currentEntry.get());
|
||||
|
||||
currentEntry = entry;
|
||||
currentBrowsingContext = parent;
|
||||
}
|
||||
|
||||
currentEntry = (aBrowsingContext->Top()->*GetWeakRef)().get();
|
||||
} else if ((currentEntry = (aBrowsingContext->*GetWeakRef)())) {
|
||||
currentEntry->Update(aUpdate);
|
||||
|
||||
CanonicalBrowsingContext* currentBrowsingContext = aBrowsingContext;
|
||||
while (CanonicalBrowsingContext* parent =
|
||||
currentBrowsingContext->GetParent()) {
|
||||
if (!currentEntry || !currentEntry->IsEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
T* parentEntry = (parent->*GetWeakRef)().get();
|
||||
RemoveEntry(currentBrowsingContext, parentEntry);
|
||||
|
||||
currentEntry = parentEntry;
|
||||
currentBrowsingContext = parent;
|
||||
}
|
||||
|
||||
if (currentEntry && currentEntry->IsEmpty()) {
|
||||
currentEntry = nullptr;
|
||||
} else {
|
||||
currentEntry = (aBrowsingContext->Top()->*GetWeakRef)().get();
|
||||
}
|
||||
}
|
||||
|
||||
*aEntry = currentEntry.forget().take();
|
||||
}
|
||||
|
||||
void BrowserSessionStore::UpdateSessionStore(
|
||||
CanonicalBrowsingContext* aBrowsingContext,
|
||||
const Maybe<sessionstore::FormData>& aFormData,
|
||||
const Maybe<nsPoint>& aScrollPosition, uint32_t aEpoch) {
|
||||
if (!aFormData && !aScrollPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ShouldUpdateSessionStore(aBrowsingContext, aEpoch)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aFormData) {
|
||||
UpdateSessionStoreField<
|
||||
SessionStoreFormData,
|
||||
&CanonicalBrowsingContext::GetSessionStoreFormDataRef>(
|
||||
aBrowsingContext, *aFormData, getter_AddRefs(mFormData));
|
||||
}
|
||||
|
||||
if (aScrollPosition) {
|
||||
UpdateSessionStoreField<
|
||||
SessionStoreScrollData,
|
||||
&CanonicalBrowsingContext::GetSessionStoreScrollDataRef>(
|
||||
aBrowsingContext, *aScrollPosition, getter_AddRefs(mScrollData));
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserSessionStore::RemoveSessionStore(
|
||||
CanonicalBrowsingContext* aBrowsingContext) {
|
||||
if (!aBrowsingContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
CanonicalBrowsingContext* parentContext = aBrowsingContext->GetParent();
|
||||
|
||||
if (parentContext) {
|
||||
RemoveEntry(aBrowsingContext,
|
||||
parentContext->GetSessionStoreFormDataRef().get());
|
||||
|
||||
RemoveEntry(aBrowsingContext,
|
||||
parentContext->GetSessionStoreScrollDataRef().get());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (aBrowsingContext->IsTop()) {
|
||||
mFormData = nullptr;
|
||||
mScrollData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BrowserSessionStore::~BrowserSessionStore() {
|
||||
if (sSessionStore) {
|
||||
sSessionStore->Remove(mBrowsingContext->Id());
|
||||
}
|
||||
}
|
57
toolkit/components/sessionstore/BrowserSessionStore.h
Normal file
57
toolkit/components/sessionstore/BrowserSessionStore.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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_SessionStore_h
|
||||
#define mozilla_dom_SessionStore_h
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
struct nsPoint;
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
class CanonicalBrowsingContext;
|
||||
class GlobalObject;
|
||||
class SessionStoreFormData;
|
||||
class SessionStoreScrollData;
|
||||
class WindowGlobalParent;
|
||||
|
||||
namespace sessionstore {
|
||||
class FormData;
|
||||
}
|
||||
|
||||
class BrowserSessionStore final {
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowserSessionStore)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BrowserSessionStore)
|
||||
|
||||
static already_AddRefed<BrowserSessionStore> GetOrCreate(
|
||||
CanonicalBrowsingContext* aBrowsingContext);
|
||||
|
||||
SessionStoreFormData* GetFormdata();
|
||||
SessionStoreScrollData* GetScroll();
|
||||
|
||||
void UpdateSessionStore(CanonicalBrowsingContext* aBrowsingContext,
|
||||
const Maybe<sessionstore::FormData>& aFormData,
|
||||
const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
void RemoveSessionStore(CanonicalBrowsingContext* aBrowsingContext);
|
||||
|
||||
private:
|
||||
explicit BrowserSessionStore(CanonicalBrowsingContext* aBrowsingContext);
|
||||
virtual ~BrowserSessionStore();
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> mBrowsingContext;
|
||||
RefPtr<SessionStoreFormData> mFormData;
|
||||
RefPtr<SessionStoreScrollData> mScrollData;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_SessionStore_h
|
60
toolkit/components/sessionstore/PSessionStore.ipdl
Normal file
60
toolkit/components/sessionstore/PSessionStore.ipdl
Normal file
@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
include protocol PBrowser;
|
||||
include protocol PInProcess;
|
||||
include SessionStoreTypes;
|
||||
|
||||
using mozilla::dom::MaybeDiscardedBrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* The PSessionStore actor handles collection of session store data from content
|
||||
* type documents. It can be used both in a content process and in the parent
|
||||
* process. In particular it solves the problem of handling incremental updates
|
||||
* to the session store, since we're collecting from potentially several content
|
||||
* processes.
|
||||
*/
|
||||
async protocol PSessionStore
|
||||
{
|
||||
manager PBrowser or PInProcess;
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Sends data to be stored and instructions to the session store to
|
||||
* potentially collect data in the parent. This is data that is not
|
||||
* collected incrementally.
|
||||
*/
|
||||
async SessionStoreUpdate(
|
||||
nsCString? aDocShellCaps, bool? aPrivateMode, bool aNeedCollectSHistory,
|
||||
uint32_t aEpoch);
|
||||
|
||||
/**
|
||||
* Sends data to be stored to the session store. The collected data
|
||||
* is all the collected changed data from all the in-process documents
|
||||
* in the process in which the SessionStoreChild actor lives.
|
||||
*/
|
||||
async IncrementalSessionStoreUpdate(
|
||||
MaybeDiscardedBrowsingContext aBrowsingContext, FormData? aFormData,
|
||||
nsPoint? aScrollPosition, uint32_t aEpoch);
|
||||
|
||||
/**
|
||||
* Drop all the collected data associated with the provided browsing
|
||||
* context.
|
||||
*/
|
||||
async ResetSessionStore(
|
||||
MaybeDiscardedBrowsingContext aBrowsingContext, uint32_t aEpoch);
|
||||
|
||||
child:
|
||||
async FlushTabState() returns(bool aHadContext);
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -10,13 +10,23 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
|
||||
#include "nsBaseHashtable.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace {
|
||||
constexpr auto kInput = u"input"_ns;
|
||||
@ -28,13 +38,28 @@ static constexpr char kInterval[] = "browser.sessionstore.interval";
|
||||
static const char* kObservedPrefs[] = {kNoAutoUpdates, kInterval, nullptr};
|
||||
} // namespace
|
||||
|
||||
namespace mozilla::dom {
|
||||
inline void ImplCycleCollectionUnlink(
|
||||
SessionStoreChangeListener::SessionStoreChangeTable& aField) {
|
||||
aField.Clear();
|
||||
}
|
||||
|
||||
inline void ImplCycleCollectionTraverse(
|
||||
nsCycleCollectionTraversalCallback& aCallback,
|
||||
const SessionStoreChangeListener::SessionStoreChangeTable& aField,
|
||||
const char* aName, uint32_t aFlags = 0) {
|
||||
for (auto iter = aField.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
CycleCollectionNoteChild(aCallback, iter.Key(), aName, aFlags);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(SessionStoreChangeListener, mBrowsingContext,
|
||||
mCurrentEventTarget)
|
||||
mCurrentEventTarget, mSessionStoreChild,
|
||||
mSessionStoreChanges)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStoreChangeListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINamed)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_END
|
||||
@ -42,10 +67,22 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStoreChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStoreChangeListener)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStoreChangeListener::GetName(nsACString& aName) {
|
||||
aName.AssignLiteral("SessionStoreChangeListener");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStoreChangeListener::Notify(nsITimer* aTimer) {
|
||||
FlushSessionStore();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStoreChangeListener::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData) {
|
||||
Flush();
|
||||
FlushSessionStore();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -62,45 +99,33 @@ SessionStoreChangeListener::HandleEvent(dom::Event* aEvent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WindowGlobalChild* windowChild = inner->GetWindowGlobalChild();
|
||||
if (!windowChild) {
|
||||
WindowContext* windowContext = inner->GetWindowContext();
|
||||
if (!windowContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<BrowsingContext> browsingContext = windowChild->BrowsingContext();
|
||||
RefPtr<BrowsingContext> browsingContext = windowContext->GetBrowsingContext();
|
||||
if (!browsingContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool dynamic = false;
|
||||
BrowsingContext* current = browsingContext;
|
||||
while (current) {
|
||||
if ((dynamic = current->CreatedDynamically())) {
|
||||
break;
|
||||
}
|
||||
current = current->GetParent();
|
||||
}
|
||||
|
||||
if (dynamic) {
|
||||
if (browsingContext->IsDynamic()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
|
||||
RefPtr<SessionStoreDataCollector> collector =
|
||||
SessionStoreDataCollector::CollectSessionStoreData(windowChild);
|
||||
|
||||
if (!collector) {
|
||||
return NS_OK;
|
||||
}
|
||||
Change change = Change::None;
|
||||
|
||||
if (eventType == kInput) {
|
||||
collector->RecordInputChange();
|
||||
change = Change::Input;
|
||||
} else if (eventType == kScroll) {
|
||||
collector->RecordScrollChange();
|
||||
change = Change::Scroll;
|
||||
}
|
||||
|
||||
RecordChange(windowContext, EnumSet(change));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -128,13 +153,134 @@ void SessionStoreChangeListener::UpdateEventTargets() {
|
||||
AddEventListeners();
|
||||
}
|
||||
|
||||
void SessionStoreChangeListener::Flush() {
|
||||
mBrowsingContext->FlushSessionStore();
|
||||
static void CollectFormData(Document* aDocument,
|
||||
Maybe<sessionstore::FormData>& aFormData) {
|
||||
aFormData.emplace();
|
||||
auto& formData = aFormData.ref();
|
||||
uint32_t size = SessionStoreUtils::CollectFormData(aDocument, formData);
|
||||
|
||||
Element* body = aDocument->GetBody();
|
||||
if (aDocument->HasFlag(NODE_IS_EDITABLE) && body) {
|
||||
IgnoredErrorResult result;
|
||||
body->GetInnerHTML(formData.innerHTML(), result);
|
||||
size += formData.innerHTML().Length();
|
||||
if (!result.Failed()) {
|
||||
formData.hasData() = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!formData.hasData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIURI* documentURI = aDocument->GetDocumentURI();
|
||||
if (!documentURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
documentURI->GetSpecIgnoringRef(formData.uri());
|
||||
|
||||
if (size > StaticPrefs::browser_sessionstore_dom_form_max_limit()) {
|
||||
aFormData = Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChangeListener::FlushSessionStore() {
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
|
||||
for (auto& iter : mSessionStoreChanges) {
|
||||
WindowContext* windowContext = iter.GetKey();
|
||||
if (!windowContext) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<Document> document = windowContext->GetDocument();
|
||||
if (!document) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EnumSet<Change> changes = iter.GetData();
|
||||
Maybe<sessionstore::FormData> maybeFormData;
|
||||
if (changes.contains(Change::Input)) {
|
||||
CollectFormData(document, maybeFormData);
|
||||
}
|
||||
|
||||
Maybe<nsPoint> maybeScroll;
|
||||
PresShell* presShell = document->GetPresShell();
|
||||
|
||||
if (presShell && changes.contains(Change::Scroll)) {
|
||||
maybeScroll = Some(presShell->GetVisualViewportOffset());
|
||||
}
|
||||
|
||||
mSessionStoreChild->SendIncrementalSessionStoreUpdate(
|
||||
windowContext->GetBrowsingContext(), maybeFormData, maybeScroll,
|
||||
mEpoch);
|
||||
}
|
||||
|
||||
mSessionStoreChanges.Clear();
|
||||
|
||||
mSessionStoreChild->UpdateSessionStore();
|
||||
}
|
||||
|
||||
/* static */
|
||||
SessionStoreChangeListener* SessionStoreChangeListener::CollectSessionStoreData(
|
||||
WindowContext* aWindowContext, const EnumSet<Change>& aChanges) {
|
||||
SessionStoreChild* sessionStoreChild =
|
||||
SessionStoreChild::From(aWindowContext->GetWindowGlobalChild());
|
||||
if (!sessionStoreChild) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SessionStoreChangeListener* sessionStoreChangeListener =
|
||||
sessionStoreChild->GetSessionStoreChangeListener();
|
||||
|
||||
if (!sessionStoreChangeListener) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sessionStoreChangeListener->RecordChange(aWindowContext, aChanges);
|
||||
|
||||
return sessionStoreChangeListener;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void SessionStoreChangeListener::FlushAllSessionStoreData(
|
||||
WindowContext* aWindowContext) {
|
||||
EnumSet<Change> allChanges(Change::Input, Change::Scroll);
|
||||
SessionStoreChangeListener* listener =
|
||||
CollectSessionStoreData(aWindowContext, allChanges);
|
||||
if (listener) {
|
||||
listener->FlushSessionStore();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChangeListener::SetActor(
|
||||
SessionStoreChild* aSessionStoreChild) {
|
||||
mSessionStoreChild = aSessionStoreChild;
|
||||
}
|
||||
|
||||
void SessionStoreChangeListener::RecordChange(WindowContext* aWindowContext,
|
||||
EnumSet<Change> aChange) {
|
||||
EnsureTimer();
|
||||
|
||||
Unused << mSessionStoreChanges.WithEntryHandle(
|
||||
aWindowContext, [&](auto entryHandle) -> EnumSet<Change>& {
|
||||
if (entryHandle) {
|
||||
*entryHandle += aChange;
|
||||
return *entryHandle;
|
||||
}
|
||||
|
||||
return entryHandle.Insert(aChange);
|
||||
});
|
||||
}
|
||||
|
||||
SessionStoreChangeListener::SessionStoreChangeListener(
|
||||
BrowsingContext* aBrowsingContext)
|
||||
: mBrowsingContext(aBrowsingContext) {}
|
||||
: mBrowsingContext(aBrowsingContext),
|
||||
mEpoch(aBrowsingContext->GetSessionStoreEpoch()) {}
|
||||
|
||||
void SessionStoreChangeListener::Init() {
|
||||
AddEventListeners();
|
||||
@ -167,4 +313,19 @@ void SessionStoreChangeListener::RemoveEventListeners() {
|
||||
mCurrentEventTarget = nullptr;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
void SessionStoreChangeListener::EnsureTimer() {
|
||||
if (mTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
|
||||
auto result = NS_NewTimerWithCallback(
|
||||
this, StaticPrefs::browser_sessionstore_interval(),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (result.isErr()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTimer = result.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -9,25 +9,39 @@
|
||||
|
||||
#include "ErrorList.h"
|
||||
|
||||
#include "PLDHashTable.h"
|
||||
#include "mozilla/EnumSet.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsHashtablesFwd.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
#include "mozilla/EnumSet.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Result.h"
|
||||
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BrowsingContext;
|
||||
class Element;
|
||||
class EventTarget;
|
||||
class SessionStoreDataCollector;
|
||||
class BrowsingContext;
|
||||
class SessionStoreChild;
|
||||
class WindowContext;
|
||||
|
||||
class SessionStoreChangeListener final : public nsIObserver,
|
||||
class SessionStoreChangeListener final : public nsINamed,
|
||||
public nsIObserver,
|
||||
public nsITimerCallback,
|
||||
public nsIDOMEventListener {
|
||||
public:
|
||||
NS_DECL_NSINAMED
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SessionStoreChangeListener,
|
||||
@ -40,7 +54,29 @@ class SessionStoreChangeListener final : public nsIObserver,
|
||||
|
||||
void UpdateEventTargets();
|
||||
|
||||
void Flush();
|
||||
void FlushSessionStore();
|
||||
|
||||
enum class Change { None, Input, Scroll };
|
||||
|
||||
static SessionStoreChangeListener* CollectSessionStoreData(
|
||||
WindowContext* aWindowContext, const EnumSet<Change>& aChanges);
|
||||
|
||||
static void FlushAllSessionStoreData(WindowContext* aWindowContext);
|
||||
|
||||
void SetActor(SessionStoreChild* aSessionStoreChild);
|
||||
|
||||
void SetEpoch(uint32_t aEpoch) { mEpoch = aEpoch; }
|
||||
|
||||
uint32_t GetEpoch() const { return mEpoch; }
|
||||
|
||||
BrowsingContext* GetBrowsingContext() const { return mBrowsingContext; }
|
||||
|
||||
private:
|
||||
void RecordChange(WindowContext* aWindowContext, EnumSet<Change> aChanges);
|
||||
|
||||
public:
|
||||
using SessionStoreChangeTable =
|
||||
nsTHashMap<RefPtr<WindowContext>, EnumSet<Change>>;
|
||||
|
||||
private:
|
||||
explicit SessionStoreChangeListener(BrowsingContext* aBrowsingContext);
|
||||
@ -53,8 +89,15 @@ class SessionStoreChangeListener final : public nsIObserver,
|
||||
void AddEventListeners();
|
||||
void RemoveEventListeners();
|
||||
|
||||
void EnsureTimer();
|
||||
|
||||
RefPtr<BrowsingContext> mBrowsingContext;
|
||||
RefPtr<EventTarget> mCurrentEventTarget;
|
||||
|
||||
uint32_t mEpoch;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
RefPtr<SessionStoreChild> mSessionStoreChild;
|
||||
SessionStoreChangeTable mSessionStoreChanges;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
226
toolkit/components/sessionstore/SessionStoreChild.cpp
Normal file
226
toolkit/components/sessionstore/SessionStoreChild.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/InProcessChild.h"
|
||||
#include "mozilla/dom/InProcessParent.h"
|
||||
#include "mozilla/dom/BrowserSessionStore.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreParent.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/ipc/Endpoint.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsFrameLoader.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
class nsIDocShell;
|
||||
|
||||
static already_AddRefed<TabListener> CreateTabListener(nsIDocShell* aDocShell) {
|
||||
RefPtr<TabListener> tabListener =
|
||||
mozilla::MakeRefPtr<TabListener>(aDocShell, nullptr);
|
||||
nsresult rv = tabListener->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return tabListener.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<SessionStoreChild> SessionStoreChild::GetOrCreate(
|
||||
BrowsingContext* aBrowsingContext, Element* aOwnerElement) {
|
||||
RefPtr<TabListener> tabListener =
|
||||
CreateTabListener(aBrowsingContext->GetDocShell());
|
||||
if (!tabListener) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SessionStoreChangeListener> sessionStoreChangeListener =
|
||||
SessionStoreChangeListener::Create(aBrowsingContext);
|
||||
if (!sessionStoreChangeListener) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SessionStoreChild> sessionStoreChild =
|
||||
new SessionStoreChild(tabListener, sessionStoreChangeListener);
|
||||
|
||||
sessionStoreChangeListener->SetActor(sessionStoreChild);
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aOwnerElement);
|
||||
InProcessChild* inProcessChild = InProcessChild::Singleton();
|
||||
InProcessParent* inProcessParent = InProcessParent::Singleton();
|
||||
if (!inProcessChild || !inProcessParent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BrowserSessionStore> sessionStore =
|
||||
BrowserSessionStore::GetOrCreate(aBrowsingContext->Canonical()->Top());
|
||||
if (!sessionStore) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CanonicalBrowsingContext* browsingContext = aBrowsingContext->Canonical();
|
||||
RefPtr<SessionStoreParent> sessionStoreParent =
|
||||
new SessionStoreParent(browsingContext, sessionStore);
|
||||
ManagedEndpoint<PSessionStoreParent> endpoint =
|
||||
inProcessChild->OpenPSessionStoreEndpoint(sessionStoreChild);
|
||||
inProcessParent->BindPSessionStoreEndpoint(std::move(endpoint),
|
||||
sessionStoreParent);
|
||||
} else {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aOwnerElement);
|
||||
RefPtr<BrowserChild> browserChild =
|
||||
BrowserChild::GetFrom(aBrowsingContext->GetDOMWindow());
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(browserChild);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aBrowsingContext->IsInProcess());
|
||||
sessionStoreChild = static_cast<SessionStoreChild*>(
|
||||
browserChild->SendPSessionStoreConstructor(sessionStoreChild));
|
||||
}
|
||||
|
||||
return sessionStoreChild.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
SessionStoreChild* SessionStoreChild::From(WindowGlobalChild* aWindowChild) {
|
||||
if (!aWindowChild) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If `aWindowChild` is inprocess
|
||||
if (RefPtr<BrowserChild> browserChild = aWindowChild->GetBrowserChild()) {
|
||||
return browserChild->GetSessionStoreChild();
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WindowGlobalParent* windowParent = aWindowChild->WindowContext()->Canonical();
|
||||
if (!windowParent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<nsFrameLoader> frameLoader = windowParent->GetRootFrameLoader();
|
||||
if (!frameLoader) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return frameLoader->GetSessionStoreChild();
|
||||
}
|
||||
|
||||
SessionStoreChild::SessionStoreChild(
|
||||
TabListener* aSessionStoreListener,
|
||||
SessionStoreChangeListener* aSessionStoreChangeListener)
|
||||
: mSessionStoreListener(aSessionStoreListener),
|
||||
mSessionStoreChangeListener(aSessionStoreChangeListener) {}
|
||||
|
||||
void SessionStoreChild::SetEpoch(uint32_t aEpoch) {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->SetEpoch(aEpoch);
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->SetEpoch(aEpoch);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChild::SetOwnerContent(Element* aElement) {
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->FlushSessionStore();
|
||||
}
|
||||
|
||||
if (!aElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->SetOwnerContent(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChild::Stop() {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->RemoveListeners();
|
||||
mSessionStoreListener = nullptr;
|
||||
}
|
||||
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChild::UpdateEventTargets() {
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->UpdateEventTargets();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChild::UpdateSessionStore() {
|
||||
if (!mSessionStoreListener) {
|
||||
// This is the case when we're shutting down, and expect a final update.
|
||||
Unused << SendSessionStoreUpdate(Nothing(), Nothing(), false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ContentSessionStore> store = mSessionStoreListener->GetSessionStore();
|
||||
|
||||
Maybe<nsCString> docShellCaps;
|
||||
if (store->IsDocCapChanged()) {
|
||||
docShellCaps.emplace(store->GetDocShellCaps());
|
||||
}
|
||||
|
||||
Maybe<bool> privatedMode;
|
||||
if (store->IsPrivateChanged()) {
|
||||
privatedMode.emplace(store->GetPrivateModeEnabled());
|
||||
}
|
||||
|
||||
Unused << SendSessionStoreUpdate(docShellCaps, privatedMode,
|
||||
store->GetAndClearSHistoryChanged(),
|
||||
mSessionStoreListener->GetEpoch());
|
||||
}
|
||||
|
||||
void SessionStoreChild::FlushSessionStore() {
|
||||
if (mSessionStoreChangeListener) {
|
||||
mSessionStoreChangeListener->FlushSessionStore();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreChild::UpdateSHistoryChanges() {
|
||||
if (mSessionStoreListener) {
|
||||
mSessionStoreListener->UpdateSHistoryChanges();
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStoreChild::RecvFlushTabState(
|
||||
FlushTabStateResolver&& aResolver) {
|
||||
if (mSessionStoreChangeListener) {
|
||||
if (BrowsingContext* context =
|
||||
mSessionStoreChangeListener->GetBrowsingContext()) {
|
||||
if (auto* docShell = nsDocShell::Cast(context->GetDocShell())) {
|
||||
docShell->CollectWireframe();
|
||||
}
|
||||
}
|
||||
|
||||
mSessionStoreChangeListener->FlushSessionStore();
|
||||
}
|
||||
aResolver(true);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(SessionStoreChild, mSessionStoreListener,
|
||||
mSessionStoreChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SessionStoreChild, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SessionStoreChild, Release)
|
57
toolkit/components/sessionstore/SessionStoreChild.h
Normal file
57
toolkit/components/sessionstore/SessionStoreChild.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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_SessionStoreChild_h
|
||||
#define mozilla_dom_SessionStoreChild_h
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/dom/PSessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreListener.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
class BrowsingContext;
|
||||
class SessionStoreChangeListener;
|
||||
class TabListener;
|
||||
|
||||
class SessionStoreChild final : public PSessionStoreChild {
|
||||
public:
|
||||
static already_AddRefed<SessionStoreChild> GetOrCreate(
|
||||
BrowsingContext* aBrowsingContext, Element* aOwnerElement = nullptr);
|
||||
|
||||
static SessionStoreChild* From(WindowGlobalChild* aWindowChild);
|
||||
|
||||
void SetEpoch(uint32_t aEpoch);
|
||||
void SetOwnerContent(Element* aElement);
|
||||
void Stop();
|
||||
void UpdateEventTargets();
|
||||
void UpdateSessionStore();
|
||||
void FlushSessionStore();
|
||||
void UpdateSHistoryChanges();
|
||||
|
||||
SessionStoreChangeListener* GetSessionStoreChangeListener() const {
|
||||
return mSessionStoreChangeListener;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvFlushTabState(FlushTabStateResolver&& aResolver);
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SessionStoreChild)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(SessionStoreChild)
|
||||
|
||||
private:
|
||||
SessionStoreChild(TabListener* aSessionStoreListener,
|
||||
SessionStoreChangeListener* aSessionStoreChangeListener);
|
||||
~SessionStoreChild() = default;
|
||||
|
||||
RefPtr<TabListener> mSessionStoreListener;
|
||||
RefPtr<SessionStoreChangeListener> mSessionStoreChangeListener;
|
||||
};
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_SessionStoreChild_h
|
@ -1,180 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/dom/SessionStoreDataCollector.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIContentInlines.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(SessionStoreDataCollector, mWindowChild, mTimer)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStoreDataCollector)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINamed)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStoreDataCollector)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStoreDataCollector)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStoreDataCollector::GetName(nsACString& aName) {
|
||||
aName.AssignLiteral("SessionStoreDataCollector");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SessionStoreDataCollector::Notify(nsITimer* aTimer) {
|
||||
Collect();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<SessionStoreDataCollector>
|
||||
SessionStoreDataCollector::CollectSessionStoreData(
|
||||
WindowGlobalChild* aWindowChild) {
|
||||
MOZ_RELEASE_ASSERT(SessionStoreUtils::NATIVE_LISTENER);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWindowChild);
|
||||
|
||||
RefPtr<SessionStoreDataCollector> listener =
|
||||
aWindowChild->GetSessionStoreDataCollector();
|
||||
|
||||
uint32_t epoch =
|
||||
aWindowChild->BrowsingContext()->Top()->GetSessionStoreEpoch();
|
||||
if (listener) {
|
||||
MOZ_DIAGNOSTIC_ASSERT_IF(
|
||||
!StaticPrefs::browser_sessionstore_debug_no_auto_updates(),
|
||||
listener->mTimer);
|
||||
if (listener->mEpoch == epoch) {
|
||||
return listener.forget();
|
||||
}
|
||||
if (listener->mTimer) {
|
||||
listener->mTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
listener = new SessionStoreDataCollector(aWindowChild, epoch);
|
||||
|
||||
if (!StaticPrefs::browser_sessionstore_debug_no_auto_updates()) {
|
||||
auto result = NS_NewTimerWithCallback(
|
||||
listener, StaticPrefs::browser_sessionstore_interval(),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (result.isErr()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
listener->mTimer = result.unwrap();
|
||||
}
|
||||
|
||||
aWindowChild->SetSessionStoreDataCollector(listener);
|
||||
return listener.forget();
|
||||
}
|
||||
|
||||
void SessionStoreDataCollector::RecordInputChange() { mInputChanged = true; }
|
||||
|
||||
void SessionStoreDataCollector::RecordScrollChange() { mScrollChanged = true; }
|
||||
|
||||
void SessionStoreDataCollector::Flush() { Collect(); }
|
||||
|
||||
void SessionStoreDataCollector::Cancel() {
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
|
||||
mWindowChild->SetSessionStoreDataCollector(nullptr);
|
||||
}
|
||||
|
||||
void SessionStoreDataCollector::Collect() {
|
||||
if (this != mWindowChild->GetSessionStoreDataCollector()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
|
||||
nsGlobalWindowInner* inner = mWindowChild->GetWindowGlobal();
|
||||
if (!inner) {
|
||||
return;
|
||||
}
|
||||
|
||||
Document* document = inner->GetDocument();
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<sessionstore::FormData> maybeFormData;
|
||||
if (mInputChanged) {
|
||||
maybeFormData.emplace();
|
||||
auto& formData = maybeFormData.ref();
|
||||
uint32_t size = SessionStoreUtils::CollectFormData(document, formData);
|
||||
|
||||
Element* body = document->GetBody();
|
||||
if (body && body->IsInDesignMode()) {
|
||||
IgnoredErrorResult result;
|
||||
body->GetInnerHTML(formData.innerHTML(), result);
|
||||
size += formData.innerHTML().Length();
|
||||
if (!result.Failed()) {
|
||||
formData.hasData() = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > StaticPrefs::browser_sessionstore_dom_form_max_limit()) {
|
||||
maybeFormData = Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
PresShell* presShell = document->GetPresShell();
|
||||
Maybe<nsPoint> maybeScroll;
|
||||
if (mScrollChanged && presShell) {
|
||||
maybeScroll = Some(presShell->GetVisualViewportOffset());
|
||||
}
|
||||
|
||||
if (!mWindowChild->CanSend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (RefPtr<WindowGlobalParent> windowParent =
|
||||
mWindowChild->GetParentActor()) {
|
||||
windowParent->WriteFormDataAndScrollToSessionStore(maybeFormData,
|
||||
maybeScroll, mEpoch);
|
||||
} else {
|
||||
mWindowChild->SendUpdateSessionStore(maybeFormData, maybeScroll, mEpoch);
|
||||
}
|
||||
|
||||
mWindowChild->SetSessionStoreDataCollector(nullptr);
|
||||
}
|
||||
|
||||
SessionStoreDataCollector::SessionStoreDataCollector(
|
||||
WindowGlobalChild* aWindowChild, uint32_t aEpoch)
|
||||
: mWindowChild(aWindowChild),
|
||||
mTimer(nullptr),
|
||||
mEpoch(aEpoch),
|
||||
mInputChanged(false),
|
||||
mScrollChanged(false) {}
|
||||
|
||||
SessionStoreDataCollector::~SessionStoreDataCollector() {
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
@ -1,68 +0,0 @@
|
||||
/* -*- 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_SessionStoreDataCollector_h
|
||||
#define mozilla_dom_SessionStoreDataCollector_h
|
||||
|
||||
#include "ErrorList.h"
|
||||
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BrowserChild;
|
||||
class EventTarget;
|
||||
class WindowGlobalChild;
|
||||
|
||||
namespace sessionstore {
|
||||
class FormData;
|
||||
}
|
||||
|
||||
class SessionStoreDataCollector final : public nsITimerCallback,
|
||||
public nsINamed {
|
||||
public:
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSINAMED
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SessionStoreDataCollector,
|
||||
nsITimerCallback)
|
||||
|
||||
enum class Change { Input, Scroll };
|
||||
|
||||
static already_AddRefed<SessionStoreDataCollector> CollectSessionStoreData(
|
||||
WindowGlobalChild* aWindowChild);
|
||||
|
||||
void RecordInputChange();
|
||||
void RecordScrollChange();
|
||||
|
||||
void Flush();
|
||||
|
||||
void Cancel();
|
||||
|
||||
private:
|
||||
void Collect();
|
||||
|
||||
nsresult Apply(Maybe<sessionstore::FormData>&& aFormData,
|
||||
Maybe<nsPoint>&& aScroll);
|
||||
|
||||
SessionStoreDataCollector(WindowGlobalChild* aWindowChild, uint32_t aEpoch);
|
||||
~SessionStoreDataCollector();
|
||||
|
||||
RefPtr<WindowGlobalChild> mWindowChild;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
uint32_t mEpoch;
|
||||
bool mInputChanged : 1;
|
||||
bool mScrollChanged : 1;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_SessionStoreDataCollector_h
|
172
toolkit/components/sessionstore/SessionStoreFormData.cpp
Normal file
172
toolkit/components/sessionstore/SessionStoreFormData.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/dom/SessionStoreFormData.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/BrowserSessionStoreBinding.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "js/JSON.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStoreFormData)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStoreFormData)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WEAK_PTR(SessionStoreFormData, mChildren)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStoreFormData)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsISupports* SessionStoreFormData::GetParentObject() const {
|
||||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
}
|
||||
|
||||
JSObject* SessionStoreFormData::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return SessionStoreFormData_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void SessionStoreFormData::GetUrl(nsACString& aUrl) const {
|
||||
if (mUrl.IsEmpty()) {
|
||||
aUrl.SetIsVoid(true);
|
||||
} else {
|
||||
aUrl = mUrl;
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreFormData::GetId(
|
||||
JSContext* aCx,
|
||||
Nullable<Record<nsString, OwningStringOrBooleanOrObject>>& aId) {
|
||||
if (mId.IsEmpty() ||
|
||||
NS_FAILED(SessionStoreUtils::ConstructFormDataValues(
|
||||
aCx, mId, aId.SetValue().Entries(), mParseSessionData))) {
|
||||
aId.SetNull();
|
||||
}
|
||||
|
||||
// SessionStoreFormData.id is now stored in a slot, so we can free our
|
||||
// internal state.
|
||||
mId.Clear();
|
||||
}
|
||||
|
||||
void SessionStoreFormData::GetXpath(
|
||||
JSContext* aCx,
|
||||
Nullable<Record<nsString, OwningStringOrBooleanOrObject>>& aXpath) {
|
||||
if (mXpath.IsEmpty() ||
|
||||
NS_FAILED(SessionStoreUtils::ConstructFormDataValues(
|
||||
aCx, mXpath, aXpath.SetValue().Entries(), mParseSessionData))) {
|
||||
aXpath.SetNull();
|
||||
}
|
||||
|
||||
// SessionStoreFormData.xpath is now stored in a slot, so we can free our
|
||||
// internal state.
|
||||
mXpath.Clear();
|
||||
}
|
||||
|
||||
void SessionStoreFormData::GetInnerHTML(nsAString& aInnerHTML) {
|
||||
if (mInnerHTML.IsEmpty()) {
|
||||
SetDOMStringToNull(aInnerHTML);
|
||||
} else {
|
||||
aInnerHTML = mInnerHTML;
|
||||
}
|
||||
|
||||
// SessionStoreFormData.innerHTML is now stored in a slot, so we can free our
|
||||
// internal state.
|
||||
mInnerHTML.SetIsVoid(true);
|
||||
}
|
||||
|
||||
SessionStoreFormData::ChildrenArray& SessionStoreFormData::Children() {
|
||||
return mChildren;
|
||||
}
|
||||
|
||||
void SessionStoreFormData::GetChildren(
|
||||
Nullable<ChildrenArray>& aChildren) const {
|
||||
if (!mChildren.IsEmpty()) {
|
||||
aChildren.SetValue() = mChildren.Clone();
|
||||
} else {
|
||||
aChildren.SetNull();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreFormData::ToJSON(JSContext* aCx,
|
||||
JS::MutableHandleObject aRetval) {
|
||||
JS::RootedObject self(aCx);
|
||||
{
|
||||
JS::RootedValue value(aCx);
|
||||
if (!GetOrCreateDOMReflector(aCx, this, &value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.set(value.toObjectOrNull());
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> result(aCx, JS_NewPlainObject(aCx));
|
||||
|
||||
if (!IsEmpty()) {
|
||||
for (const auto& name :
|
||||
{u"url"_ns, u"id"_ns, u"xpath"_ns, u"innerHTML"_ns}) {
|
||||
if (!SessionStoreUtils::CopyProperty(aCx, result, self, name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SessionStoreUtils::CopyChildren(aCx, result, mChildren);
|
||||
}
|
||||
|
||||
aRetval.set(result);
|
||||
}
|
||||
|
||||
void SessionStoreFormData::Update(const CollectedType& aFormData) {
|
||||
SessionStoreFormData_Binding::ClearCachedUrlValue(this);
|
||||
SessionStoreFormData_Binding::ClearCachedIdValue(this);
|
||||
SessionStoreFormData_Binding::ClearCachedXpathValue(this);
|
||||
SessionStoreFormData_Binding::ClearCachedInnerHTMLValue(this);
|
||||
|
||||
if (!aFormData.hasData()) {
|
||||
mParseSessionData = false;
|
||||
mHasData = false;
|
||||
mUrl = ""_ns;
|
||||
mId.Clear();
|
||||
mXpath.Clear();
|
||||
mInnerHTML = u""_ns;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mHasData = true;
|
||||
|
||||
mUrl = aFormData.uri();
|
||||
// We want to avoid saving data for about:sessionrestore as a string.
|
||||
// Since it's stored in the form as stringified JSON, stringifying
|
||||
// further causes an explosion of escape characters. cf. bug 467409
|
||||
mParseSessionData =
|
||||
mUrl == "about:sessionrestore"_ns || mUrl == "about:welcomeback"_ns;
|
||||
|
||||
mInnerHTML = aFormData.innerHTML();
|
||||
|
||||
mId.Assign(aFormData.id());
|
||||
mXpath.Assign(aFormData.xpath());
|
||||
}
|
||||
|
||||
void SessionStoreFormData::ClearCachedChildren() {
|
||||
SessionStoreFormData_Binding::ClearCachedChildrenValue(this);
|
||||
}
|
||||
|
||||
/* static */ bool SessionStoreFormData::HasData(
|
||||
const CollectedType& aFormData) {
|
||||
return aFormData.hasData();
|
||||
}
|
||||
|
||||
bool SessionStoreFormData::IsEmpty() const {
|
||||
return !mHasData && mChildren.IsEmpty();
|
||||
}
|
83
toolkit/components/sessionstore/SessionStoreFormData.h
Normal file
83
toolkit/components/sessionstore/SessionStoreFormData.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- 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_SessionStoreFormData_h
|
||||
#define mozilla_dom_SessionStoreFormData_h
|
||||
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
namespace sessionstore {
|
||||
class FormData;
|
||||
}
|
||||
|
||||
class BrowsingContext;
|
||||
class OwningByteStringOrObjectOrNull;
|
||||
class OwningStringOrObjectOrNull;
|
||||
class WindowGlobalParent;
|
||||
|
||||
class SessionStoreFormData final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public SupportsWeakPtr {
|
||||
public:
|
||||
using CollectedType = sessionstore::FormData;
|
||||
using LocationType = WeakPtr<SessionStoreFormData>;
|
||||
using ChildrenArray = nsTArray<RefPtr<SessionStoreFormData>>;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SessionStoreFormData)
|
||||
nsISupports* GetParentObject() const;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void GetUrl(nsACString& aUrl) const;
|
||||
|
||||
void GetId(JSContext* aCx,
|
||||
Nullable<Record<nsString, OwningStringOrBooleanOrObject>>& aId);
|
||||
|
||||
void GetXpath(
|
||||
JSContext* aCx,
|
||||
Nullable<Record<nsString, OwningStringOrBooleanOrObject>>& aXpath);
|
||||
|
||||
void GetInnerHTML(nsAString& aInnerHTML);
|
||||
|
||||
ChildrenArray& Children();
|
||||
|
||||
void GetChildren(Nullable<ChildrenArray>& aChildren) const;
|
||||
|
||||
void ToJSON(JSContext* aCx, JS::MutableHandleObject aRetval);
|
||||
|
||||
void Update(const CollectedType& aFormData);
|
||||
|
||||
void ClearCachedChildren();
|
||||
|
||||
static bool HasData(const CollectedType& aFormData);
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
private:
|
||||
~SessionStoreFormData() = default;
|
||||
|
||||
bool mParseSessionData = false;
|
||||
bool mHasData = false;
|
||||
nsCString mUrl;
|
||||
nsTArray<sessionstore::FormEntry> mId;
|
||||
nsTArray<sessionstore::FormEntry> mXpath;
|
||||
nsString mInnerHTML;
|
||||
ChildrenArray mChildren;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_SessionStoreFormData_h
|
@ -17,10 +17,6 @@ interface nsISessionStoreFunctions : nsISupports {
|
||||
in jsval aPermanentKey, in uint32_t aEpoch, in boolean aCollectSHistory,
|
||||
in jsval aData);
|
||||
|
||||
void UpdateSessionStoreForWindow(
|
||||
in Element aBrowser, in BrowsingContext aBrowsingContext,
|
||||
in jsval aPermanentKey, in uint32_t aEpoch, in jsval aData);
|
||||
|
||||
void UpdateSessionStoreForStorage(
|
||||
in Element aBrowser, in BrowsingContext aBrowsingContext,
|
||||
in jsval aPermanentKey, in uint32_t aEpoch, in jsval aData);
|
||||
|
@ -28,22 +28,6 @@ function UpdateSessionStore(
|
||||
);
|
||||
}
|
||||
|
||||
function UpdateSessionStoreForWindow(
|
||||
aBrowser,
|
||||
aBrowsingContext,
|
||||
aPermanentKey,
|
||||
aEpoch,
|
||||
aData
|
||||
) {
|
||||
return SessionStoreFuncInternal.updateSessionStoreForWindow(
|
||||
aBrowser,
|
||||
aBrowsingContext,
|
||||
aPermanentKey,
|
||||
aEpoch,
|
||||
aData
|
||||
);
|
||||
}
|
||||
|
||||
function UpdateSessionStoreForStorage(
|
||||
aBrowser,
|
||||
aBrowsingContext,
|
||||
@ -60,11 +44,7 @@ function UpdateSessionStoreForStorage(
|
||||
);
|
||||
}
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"UpdateSessionStore",
|
||||
"UpdateSessionStoreForWindow",
|
||||
"UpdateSessionStoreForStorage",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["UpdateSessionStore", "UpdateSessionStoreForStorage"];
|
||||
|
||||
var SessionStoreFuncInternal = {
|
||||
updateSessionStore: function SSF_updateSessionStore(
|
||||
@ -75,12 +55,14 @@ var SessionStoreFuncInternal = {
|
||||
aCollectSHistory,
|
||||
aData
|
||||
) {
|
||||
let currentData = {};
|
||||
if (aData.docShellCaps != undefined) {
|
||||
currentData.disallow = aData.docShellCaps ? aData.docShellCaps : null;
|
||||
let { formdata, scroll } = aData;
|
||||
|
||||
if (formdata) {
|
||||
aData.formdata = formdata.toJSON();
|
||||
}
|
||||
if (aData.isPrivate != undefined) {
|
||||
currentData.isPrivate = aData.isPrivate;
|
||||
|
||||
if (scroll) {
|
||||
aData.scroll = scroll.toJSON();
|
||||
}
|
||||
|
||||
SessionStore.updateSessionStoreFromTablistener(
|
||||
@ -88,28 +70,13 @@ var SessionStoreFuncInternal = {
|
||||
aBrowsingContext,
|
||||
aPermanentKey,
|
||||
{
|
||||
data: currentData,
|
||||
data: aData,
|
||||
epoch: aEpoch,
|
||||
sHistoryNeeded: aCollectSHistory,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
updateSessionStoreForWindow: function SSF_updateSessionStoreForWindow(
|
||||
aBrowser,
|
||||
aBrowsingContext,
|
||||
aPermanentKey,
|
||||
aEpoch,
|
||||
aData
|
||||
) {
|
||||
SessionStore.updateSessionStoreFromTablistener(
|
||||
aBrowser,
|
||||
aBrowsingContext,
|
||||
aPermanentKey,
|
||||
{ data: { windowstatechange: aData }, epoch: aEpoch }
|
||||
);
|
||||
},
|
||||
|
||||
updateSessionStoreForStorage: function SSF_updateSessionStoreForWindow(
|
||||
aBrowser,
|
||||
aBrowsingContext,
|
||||
|
@ -3,6 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/dom/BrowserSessionStoreBinding.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/SessionStoreListener.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
@ -384,20 +385,21 @@ nsresult TabListener::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
bool TabListener::ForceFlushFromParent() {
|
||||
void TabListener::ForceFlushFromParent() {
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if (!mSessionStore) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
return UpdateSessionStore(true);
|
||||
|
||||
UpdateSessionStore(true);
|
||||
}
|
||||
|
||||
bool TabListener::UpdateSessionStore(bool aIsFlush) {
|
||||
void TabListener::UpdateSessionStore(bool aIsFlush) {
|
||||
if (!aIsFlush) {
|
||||
if (!mSessionStore || !mSessionStore->UpdateNeeded()) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,33 +407,33 @@ bool TabListener::UpdateSessionStore(bool aIsFlush) {
|
||||
BrowserChild* browserChild = BrowserChild::GetFrom(mDocShell);
|
||||
if (browserChild) {
|
||||
StopTimerForUpdate();
|
||||
return browserChild->UpdateSessionStore();
|
||||
browserChild->UpdateSessionStore();
|
||||
}
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
BrowsingContext* context = mDocShell->GetBrowsingContext();
|
||||
if (!context) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t chromeFlags = 0;
|
||||
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
||||
mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
if (!treeOwner) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIAppWindow> window(do_GetInterface(treeOwner));
|
||||
if (!window) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if (window && NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateSessionStoreData data;
|
||||
if (mSessionStore->IsDocCapChanged()) {
|
||||
data.mDocShellCaps.Construct() = mSessionStore->GetDocShellCaps();
|
||||
data.mDisallow.Construct() = mSessionStore->GetDocShellCaps();
|
||||
}
|
||||
if (mSessionStore->IsPrivateChanged()) {
|
||||
data.mIsPrivate.Construct() = mSessionStore->GetPrivateModeEnabled();
|
||||
@ -440,16 +442,18 @@ bool TabListener::UpdateSessionStore(bool aIsFlush) {
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
NS_ENSURE_TRUE(wrapped, false);
|
||||
if (!wrapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), data, &update)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(), context->Canonical()->Top()->PermanentKey());
|
||||
@ -458,11 +462,10 @@ bool TabListener::UpdateSessionStore(bool aIsFlush) {
|
||||
mOwnerContent, context, key, mEpoch,
|
||||
mSessionStore->GetAndClearSHistoryChanged(), update);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
StopTimerForUpdate();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TabListener::RemoveListeners() {
|
||||
|
@ -73,7 +73,7 @@ class TabListener : public nsIDOMEventListener,
|
||||
nsresult Init();
|
||||
ContentSessionStore* GetSessionStore() { return mSessionStore; }
|
||||
// the function is called only when TabListener is in parent process
|
||||
bool ForceFlushFromParent();
|
||||
void ForceFlushFromParent();
|
||||
void RemoveListeners();
|
||||
void SetEpoch(uint32_t aEpoch) { mEpoch = aEpoch; }
|
||||
uint32_t GetEpoch() { return mEpoch; }
|
||||
@ -94,7 +94,7 @@ class TabListener : public nsIDOMEventListener,
|
||||
void StopTimerForUpdate();
|
||||
void AddEventListeners();
|
||||
void RemoveEventListeners();
|
||||
bool UpdateSessionStore(bool aIsFlush = false);
|
||||
void UpdateSessionStore(bool aIsFlush = false);
|
||||
virtual ~TabListener();
|
||||
|
||||
nsCOMPtr<nsIDocShell> mDocShell;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define mozilla_dom_SessionStoreMessageUtils_h
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/ipc/IPDLParamTraits.h"
|
||||
#include "SessionStoreData.h"
|
||||
#include "SessionStoreUtils.h"
|
||||
#include "SessionStoreRestoreData.h"
|
||||
|
194
toolkit/components/sessionstore/SessionStoreParent.cpp
Normal file
194
toolkit/components/sessionstore/SessionStoreParent.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/dom/SessionStoreParent.h"
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/BrowserSessionStore.h"
|
||||
#include "mozilla/dom/BrowserSessionStoreBinding.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/InProcessChild.h"
|
||||
#include "mozilla/dom/InProcessParent.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||
#include "SessionStoreFunctions.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsImportModule.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
SessionStoreParent::SessionStoreParent(
|
||||
CanonicalBrowsingContext* aBrowsingContext,
|
||||
BrowserSessionStore* aSessionStore)
|
||||
: mBrowsingContext(aBrowsingContext), mSessionStore(aSessionStore) {}
|
||||
|
||||
static void SessionStoreUpdate(CanonicalBrowsingContext* aBrowsingContext,
|
||||
const Maybe<nsCString>& aDocShellCaps,
|
||||
const Maybe<bool>& aPrivatedMode,
|
||||
bool aNeedCollectSHistory, uint32_t aEpoch) {
|
||||
UpdateSessionStoreData data;
|
||||
if (aDocShellCaps.isSome()) {
|
||||
auto& disallow = data.mDisallow.Construct();
|
||||
if (!aDocShellCaps->IsEmpty()) {
|
||||
disallow = aDocShellCaps.value();
|
||||
} else {
|
||||
disallow.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (aPrivatedMode.isSome()) {
|
||||
data.mIsPrivate.Construct() = aPrivatedMode.value();
|
||||
}
|
||||
|
||||
RefPtr<BrowserSessionStore> sessionStore =
|
||||
BrowserSessionStore::GetOrCreate(aBrowsingContext->Top());
|
||||
|
||||
SessionStoreFormData* formData = sessionStore->GetFormdata();
|
||||
data.mFormdata.Construct(formData);
|
||||
|
||||
SessionStoreScrollData* scroll = sessionStore->GetScroll();
|
||||
data.mScroll.Construct(scroll);
|
||||
|
||||
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
|
||||
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
|
||||
if (!wrapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(wrapped->GetJSObjectGlobal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> update(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), data, &update)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::RootedValue key(jsapi.cx(), aBrowsingContext->Top()->PermanentKey());
|
||||
|
||||
Unused << funcs->UpdateSessionStore(nullptr, aBrowsingContext, key, aEpoch,
|
||||
aNeedCollectSHistory, update);
|
||||
}
|
||||
|
||||
void SessionStoreParent::FlushAllSessionStoreChildren(
|
||||
const std::function<void()>& aDone) {
|
||||
if (!mBrowsingContext) {
|
||||
aDone();
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<SessionStoreParent::FlushTabStatePromise>> flushPromises;
|
||||
|
||||
// We're special casing this for when the SessionStore{Child, Parent} have
|
||||
// been created in the same process. This is only ever true for the parent
|
||||
// process session store actor, and is needed because
|
||||
// nsFrameLoader::RequestTabStateFlush expect flushes to happen faster than we
|
||||
// can manage by using the common path of sending a message the
|
||||
// SessionStoreChild. Ideally we should be able to do just that, but not
|
||||
// without more work.
|
||||
if (InProcessParent::ChildActorFor(this)) {
|
||||
// Here we assume that the session store data collection only collect for in
|
||||
// (parent-)process content type browsing contexts, which we only flush one
|
||||
// session store actor.
|
||||
flushPromises.AppendElement(FlushSessionStore());
|
||||
} else {
|
||||
// While here we flush all participating actors.
|
||||
BrowserParent* browserParent = static_cast<BrowserParent*>(Manager());
|
||||
browserParent->VisitAll([&flushPromises](BrowserParent* aBrowser) {
|
||||
if (PSessionStoreParent* sessionStoreParent =
|
||||
SingleManagedOrNull(aBrowser->ManagedPSessionStoreParent())) {
|
||||
flushPromises.AppendElement(
|
||||
static_cast<SessionStoreParent*>(sessionStoreParent)
|
||||
->FlushSessionStore());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RefPtr<SessionStoreParent::FlushTabStatePromise::AllPromiseType>
|
||||
flushPromise = SessionStoreParent::FlushTabStatePromise::All(
|
||||
GetMainThreadSerialEventTarget(), flushPromises);
|
||||
|
||||
mBrowsingContext->UpdateSessionStoreSessionStorage([aDone, flushPromise]() {
|
||||
flushPromise->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
[aDone]() { aDone(); });
|
||||
});
|
||||
}
|
||||
|
||||
already_AddRefed<SessionStoreParent::FlushTabStatePromise>
|
||||
SessionStoreParent::FlushSessionStore() {
|
||||
if (!mBrowsingContext) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SessionStoreParent::FlushTabStatePromise> promise =
|
||||
SendFlushTabState();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void SessionStoreParent::FinalFlushAllSessionStoreChildren(
|
||||
const std::function<void()>& aDone) {
|
||||
if (!mBrowsingContext) {
|
||||
aDone();
|
||||
return;
|
||||
}
|
||||
|
||||
SessionStoreChild* sessionStoreChild =
|
||||
static_cast<SessionStoreChild*>(InProcessParent::ChildActorFor(this));
|
||||
if (!sessionStoreChild || mozilla::SessionHistoryInParent()) {
|
||||
return FlushAllSessionStoreChildren(aDone);
|
||||
}
|
||||
|
||||
sessionStoreChild->FlushSessionStore();
|
||||
mBrowsingContext->UpdateSessionStoreSessionStorage(aDone);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStoreParent::RecvSessionStoreUpdate(
|
||||
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
|
||||
const bool aNeedCollectSHistory, const uint32_t& aEpoch) {
|
||||
if (!mBrowsingContext) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
SessionStoreUpdate(mBrowsingContext, aDocShellCaps, aPrivatedMode,
|
||||
aNeedCollectSHistory, aEpoch);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStoreParent::RecvIncrementalSessionStoreUpdate(
|
||||
const MaybeDiscarded<BrowsingContext>& aBrowsingContext,
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch) {
|
||||
if (!aBrowsingContext.IsNull()) {
|
||||
mSessionStore->UpdateSessionStore(
|
||||
aBrowsingContext.GetMaybeDiscarded()->Canonical(), aFormData,
|
||||
aScrollPosition, aEpoch);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult SessionStoreParent::RecvResetSessionStore(
|
||||
const MaybeDiscarded<BrowsingContext>& aBrowsingContext, uint32_t aEpoch) {
|
||||
if (!aBrowsingContext.IsNull()) {
|
||||
mSessionStore->RemoveSessionStore(
|
||||
aBrowsingContext.GetMaybeDiscarded()->Canonical());
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(SessionStoreParent, mBrowsingContext, mSessionStore)
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SessionStoreParent, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SessionStoreParent, Release)
|
58
toolkit/components/sessionstore/SessionStoreParent.h
Normal file
58
toolkit/components/sessionstore/SessionStoreParent.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* -*- 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_SessionStoreParent_h
|
||||
#define mozilla_dom_SessionStoreParent_h
|
||||
|
||||
#include "mozilla/dom/BrowserSessionStore.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/PSessionStoreParent.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
class BrowserParent;
|
||||
|
||||
class SessionStoreParent final : public PSessionStoreParent {
|
||||
public:
|
||||
SessionStoreParent(CanonicalBrowsingContext* aBrowsingContext,
|
||||
BrowserSessionStore* aSessionStore);
|
||||
|
||||
void FlushAllSessionStoreChildren(const std::function<void()>& aDone);
|
||||
|
||||
void FinalFlushAllSessionStoreChildren(const std::function<void()>& aDone);
|
||||
|
||||
/**
|
||||
* Sends data to be stored and instructions to the session store to
|
||||
* potentially collect data in the parent.
|
||||
*/
|
||||
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
|
||||
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
|
||||
const bool aNeedCollectSHistory, const uint32_t& aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvIncrementalSessionStoreUpdate(
|
||||
const MaybeDiscarded<BrowsingContext>& aBrowsingContext,
|
||||
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
|
||||
uint32_t aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvResetSessionStore(
|
||||
const MaybeDiscarded<BrowsingContext>& aBrowsingContext, uint32_t aEpoch);
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SessionStoreParent)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(SessionStoreParent)
|
||||
|
||||
private:
|
||||
~SessionStoreParent() = default;
|
||||
|
||||
already_AddRefed<SessionStoreParent::FlushTabStatePromise>
|
||||
FlushSessionStore();
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> mBrowsingContext;
|
||||
RefPtr<BrowserSessionStore> mSessionStore;
|
||||
};
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_SessionStoreParent_h
|
123
toolkit/components/sessionstore/SessionStoreScrollData.cpp
Normal file
123
toolkit/components/sessionstore/SessionStoreScrollData.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/dom/SessionStoreScrollData.h"
|
||||
#include <utility>
|
||||
|
||||
#include "js/PropertyAndElement.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/BrowserSessionStoreBinding.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
|
||||
#include "nsPresContext.h"
|
||||
|
||||
#include "mozilla/dom/WebIDLGlobalNameHash.h"
|
||||
#include "js/PropertyDescriptor.h"
|
||||
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/dom/GeneratedAtomList.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "mozilla/dom/DOMJSClass.h"
|
||||
#include "mozilla/dom/StructuredCloneHolder.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "js/Array.h"
|
||||
#include "js/JSON.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStoreScrollData)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStoreScrollData)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WEAK_PTR(SessionStoreScrollData,
|
||||
mChildren)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStoreScrollData)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsISupports* SessionStoreScrollData::GetParentObject() const {
|
||||
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
|
||||
;
|
||||
}
|
||||
|
||||
JSObject* SessionStoreScrollData::WrapObject(
|
||||
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
|
||||
return SessionStoreScrollData_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void SessionStoreScrollData::GetScroll(nsACString& aScroll) const {
|
||||
int scrollX = nsPresContext::AppUnitsToIntCSSPixels(mScroll.x);
|
||||
int scrollY = nsPresContext::AppUnitsToIntCSSPixels(mScroll.y);
|
||||
|
||||
if ((scrollX != 0) || (scrollY != 0)) {
|
||||
aScroll = nsPrintfCString("%d,%d", scrollX, scrollY);
|
||||
} else {
|
||||
aScroll.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
|
||||
SessionStoreScrollData::ChildrenArray& SessionStoreScrollData::Children() {
|
||||
return mChildren;
|
||||
}
|
||||
|
||||
void SessionStoreScrollData::GetChildren(
|
||||
Nullable<ChildrenArray>& aChildren) const {
|
||||
if (!mChildren.IsEmpty()) {
|
||||
aChildren.SetValue() = mChildren.Clone();
|
||||
} else {
|
||||
aChildren.SetNull();
|
||||
}
|
||||
}
|
||||
|
||||
void SessionStoreScrollData::ToJSON(JSContext* aCx,
|
||||
JS::MutableHandleObject aRetval) {
|
||||
JS::RootedObject self(aCx);
|
||||
{
|
||||
JS::RootedValue value(aCx);
|
||||
if (!GetOrCreateDOMReflector(aCx, this, &value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.set(value.toObjectOrNull());
|
||||
}
|
||||
|
||||
JS::RootedObject result(aCx, JS_NewPlainObject(aCx));
|
||||
|
||||
if (!IsEmpty()) {
|
||||
if (HasData(mScroll)) {
|
||||
if (!SessionStoreUtils::CopyProperty(aCx, result, self, u"scroll"_ns)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SessionStoreUtils::CopyChildren(aCx, result, mChildren);
|
||||
}
|
||||
|
||||
aRetval.set(result);
|
||||
}
|
||||
|
||||
void SessionStoreScrollData::Update(const CollectedType& aUpdate) {
|
||||
SessionStoreScrollData_Binding::ClearCachedScrollValue(this);
|
||||
mScroll = aUpdate;
|
||||
}
|
||||
|
||||
void SessionStoreScrollData::ClearCachedChildren() {
|
||||
SessionStoreScrollData_Binding::ClearCachedChildrenValue(this);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool SessionStoreScrollData::HasData(const CollectedType& aPoint) {
|
||||
int scrollX = nsPresContext::AppUnitsToIntCSSPixels(aPoint.x);
|
||||
int scrollY = nsPresContext::AppUnitsToIntCSSPixels(aPoint.y);
|
||||
return scrollX != 0 || scrollY != 0;
|
||||
}
|
||||
|
||||
bool SessionStoreScrollData::IsEmpty() const {
|
||||
return !HasData(mScroll) && mChildren.IsEmpty();
|
||||
}
|
61
toolkit/components/sessionstore/SessionStoreScrollData.h
Normal file
61
toolkit/components/sessionstore/SessionStoreScrollData.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* -*- 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_SessionStoreScrollData_h
|
||||
#define mozilla_dom_SessionStoreScrollData_h
|
||||
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
class BrowsingContext;
|
||||
class WindowGlobalParent;
|
||||
class OwningByteStringOrObjectOrNull;
|
||||
|
||||
class SessionStoreScrollData final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public SupportsWeakPtr {
|
||||
public:
|
||||
using CollectedType = nsPoint;
|
||||
using LocationType = WeakPtr<SessionStoreScrollData>;
|
||||
using ChildrenArray = nsTArray<RefPtr<SessionStoreScrollData>>;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SessionStoreScrollData)
|
||||
nsISupports* GetParentObject() const;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void GetScroll(nsACString& aScroll) const;
|
||||
|
||||
ChildrenArray& Children();
|
||||
|
||||
void GetChildren(Nullable<ChildrenArray>& aChildren) const;
|
||||
|
||||
void ToJSON(JSContext* aCx, JS::MutableHandleObject aRetval);
|
||||
|
||||
void Update(const CollectedType& aUpdate);
|
||||
|
||||
void ClearCachedChildren();
|
||||
|
||||
static bool HasData(const CollectedType& aPoint);
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
private:
|
||||
~SessionStoreScrollData() = default;
|
||||
|
||||
nsPoint mScroll;
|
||||
nsTArray<RefPtr<SessionStoreScrollData>> mChildren;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_SessionStoreScrollData_h
|
@ -52,6 +52,7 @@ struct FormData {
|
||||
FormEntry[] id;
|
||||
FormEntry[] xpath;
|
||||
nsString innerHTML;
|
||||
nsCString uri;
|
||||
};
|
||||
|
||||
struct DocShellRestoreState {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "js/Array.h" // JS::GetArrayLength, JS::IsArrayObject
|
||||
#include "js/JSON.h"
|
||||
#include "js/PropertyAndElement.h" // JS_GetElement
|
||||
#include "js/TypeDecls.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/dom/AutocompleteInfoBinding.h"
|
||||
@ -19,6 +20,8 @@
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
|
||||
#include "mozilla/dom/SessionStoreChangeListener.h"
|
||||
#include "mozilla/dom/SessionStoreChild.h"
|
||||
#include "mozilla/dom/SessionStoreUtils.h"
|
||||
#include "mozilla/dom/txIXPathContext.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
@ -300,6 +303,10 @@ void SessionStoreUtils::RestoreScrollPosition(const GlobalObject& aGlobal,
|
||||
/* static */
|
||||
void SessionStoreUtils::RestoreScrollPosition(
|
||||
nsGlobalWindowInner& aWindow, const nsCString& aScrollPosition) {
|
||||
using Change = mozilla::dom::SessionStoreChangeListener::Change;
|
||||
SessionStoreChangeListener::CollectSessionStoreData(
|
||||
aWindow.GetWindowContext(), EnumSet<Change>(Change::Scroll));
|
||||
|
||||
nsCCharSeparatedTokenizer tokenizer(aScrollPosition, ',');
|
||||
nsAutoCString token(tokenizer.nextToken());
|
||||
int pos_X = atoi(token.get());
|
||||
@ -1203,6 +1210,7 @@ bool SessionStoreUtils::RestoreFormData(const GlobalObject& aGlobal,
|
||||
if (!aData.mUrl.WasPassed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't restore any data for the given frame if the URL
|
||||
// stored in the form data doesn't match its current URL.
|
||||
nsAutoCString url;
|
||||
@ -1210,6 +1218,11 @@ bool SessionStoreUtils::RestoreFormData(const GlobalObject& aGlobal,
|
||||
if (!aData.mUrl.Value().Equals(url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
using Change = SessionStoreChangeListener::Change;
|
||||
SessionStoreChangeListener::CollectSessionStoreData(
|
||||
aDocument.GetWindowContext(), EnumSet<Change>(Change::Input));
|
||||
|
||||
if (aData.mInnerHTML.WasPassed()) {
|
||||
SetInnerHTML(aDocument, aData.mInnerHTML.Value());
|
||||
}
|
||||
@ -1311,6 +1324,10 @@ void RestoreFormEntry(Element* aNode, const FormEntryValue& aValue) {
|
||||
void SessionStoreUtils::RestoreFormData(
|
||||
Document& aDocument, const nsString& aInnerHTML,
|
||||
const nsTArray<SessionStoreRestoreData::Entry>& aEntries) {
|
||||
using Change = SessionStoreChangeListener::Change;
|
||||
SessionStoreChangeListener::CollectSessionStoreData(
|
||||
aDocument.GetWindowContext(), EnumSet<Change>(Change::Input));
|
||||
|
||||
if (!aInnerHTML.IsEmpty()) {
|
||||
SetInnerHTML(aDocument, aInnerHTML);
|
||||
}
|
||||
@ -1698,20 +1715,31 @@ nsresult SessionStoreUtils::ConstructSessionStorageValues(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ void SessionStoreUtils::ResetSessionStore(
|
||||
BrowsingContext* aContext) {
|
||||
MOZ_RELEASE_ASSERT(NATIVE_LISTENER);
|
||||
WindowContext* windowContext = aContext->GetCurrentWindowContext();
|
||||
if (!windowContext) {
|
||||
return;
|
||||
/* static */
|
||||
bool SessionStoreUtils::CopyProperty(JSContext* aCx, JS::HandleObject aDst,
|
||||
JS::HandleObject aSrc,
|
||||
const nsAString& aName) {
|
||||
JS::RootedId name(aCx);
|
||||
const char16_t* data;
|
||||
size_t length = aName.GetData(&data);
|
||||
|
||||
if (!JS_CharsToId(aCx, JS::TwoByteChars(data, length), &name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WindowGlobalChild* windowChild = windowContext->GetWindowGlobalChild();
|
||||
if (!windowChild || !windowChild->CanSend()) {
|
||||
return;
|
||||
bool found = false;
|
||||
if (!JS_HasPropertyById(aCx, aSrc, name, &found) || !found) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t epoch = aContext->GetSessionStoreEpoch();
|
||||
JS::RootedValue value(aCx);
|
||||
if (!JS_GetPropertyById(aCx, aSrc, name, &value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Unused << windowChild->SendResetSessionStore(epoch);
|
||||
if (value.isNullOrUndefined()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return JS_DefinePropertyById(aCx, aDst, name, value, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_SessionStoreUtils_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||
@ -139,14 +140,44 @@ class SessionStoreUtils {
|
||||
const nsTArray<SSCacheCopy>& aValues,
|
||||
Record<nsCString, Record<nsString, nsString>>& aStorage);
|
||||
|
||||
static void ResetSessionStore(BrowsingContext* aContext);
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_THUNDERBIRD) || \
|
||||
defined(MOZ_SUITE)
|
||||
static constexpr bool NATIVE_LISTENER = false;
|
||||
#else
|
||||
static constexpr bool NATIVE_LISTENER = true;
|
||||
#endif
|
||||
|
||||
static bool CopyProperty(JSContext* aCx, JS::HandleObject aDst,
|
||||
JS::HandleObject aSrc, const nsAString& aName);
|
||||
|
||||
template <typename T>
|
||||
static bool CopyChildren(JSContext* aCx, JS::HandleObject aDst,
|
||||
const nsTArray<RefPtr<T>>& aChildren) {
|
||||
if (!aChildren.IsEmpty()) {
|
||||
JS::RootedObject children(aCx,
|
||||
JS::NewArrayObject(aCx, aChildren.Length()));
|
||||
|
||||
for (const auto index : IntegerRange(aChildren.Length())) {
|
||||
if (!aChildren[index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JS::RootedObject object(aCx);
|
||||
aChildren[index]->ToJSON(aCx, &object);
|
||||
|
||||
if (!JS_DefineElement(aCx, children, index, object, JSPROP_ENUMERATE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JS_DefineProperty(aCx, aDst, "children", children,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -5,21 +5,29 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
"BrowserSessionStore.h",
|
||||
"SessionStoreChangeListener.h",
|
||||
"SessionStoreChild.h",
|
||||
"SessionStoreData.h",
|
||||
"SessionStoreDataCollector.h",
|
||||
"SessionStoreFormData.h",
|
||||
"SessionStoreListener.h",
|
||||
"SessionStoreMessageUtils.h",
|
||||
"SessionStoreParent.h",
|
||||
"SessionStoreRestoreData.h",
|
||||
"SessionStoreScrollData.h",
|
||||
"SessionStoreUtils.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"BrowserSessionStore.cpp",
|
||||
"RestoreTabContentObserver.cpp",
|
||||
"SessionStoreChangeListener.cpp",
|
||||
"SessionStoreDataCollector.cpp",
|
||||
"SessionStoreChild.cpp",
|
||||
"SessionStoreFormData.cpp",
|
||||
"SessionStoreListener.cpp",
|
||||
"SessionStoreParent.cpp",
|
||||
"SessionStoreRestoreData.cpp",
|
||||
"SessionStoreScrollData.cpp",
|
||||
"SessionStoreUtils.cpp",
|
||||
]
|
||||
|
||||
@ -35,6 +43,7 @@ XPIDL_SOURCES += [
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
"PSessionStore.ipdl",
|
||||
"SessionStoreTypes.ipdlh",
|
||||
]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user