зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1597499 - Make Session Restore work in Fission, r=nika
Differential Revision: https://phabricator.services.mozilla.com/D107883
This commit is contained in:
Родитель
4dd9e85c76
Коммит
83da101af6
|
@ -56,7 +56,6 @@ function ContentRestore(chromeGlobal) {
|
||||||
"restoreTabContent",
|
"restoreTabContent",
|
||||||
"restoreDocument",
|
"restoreDocument",
|
||||||
"resetRestore",
|
"resetRestore",
|
||||||
"setRestoringDocument",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let method of EXPORTED_METHODS) {
|
for (let method of EXPORTED_METHODS) {
|
||||||
|
@ -101,13 +100,6 @@ ContentRestoreInternal.prototype = {
|
||||||
return this.chromeGlobal.docShell;
|
return this.chromeGlobal.docShell;
|
||||||
},
|
},
|
||||||
|
|
||||||
setRestoringDocument(data) {
|
|
||||||
if (!Services.appinfo.sessionHistoryInParent) {
|
|
||||||
throw new Error("This function should only be used with SHIP");
|
|
||||||
}
|
|
||||||
this._restoringDocument = data;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the process of restoring a tab. The tabData to be restored is passed
|
* Starts the process of restoring a tab. The tabData to be restored is passed
|
||||||
* in here and used throughout the restoration. The epoch (which must be
|
* in here and used throughout the restoration. The epoch (which must be
|
||||||
|
@ -224,9 +216,7 @@ ContentRestoreInternal.prototype = {
|
||||||
webNavigation.loadURI(tabData.userTypedValue, loadURIOptions);
|
webNavigation.loadURI(tabData.userTypedValue, loadURIOptions);
|
||||||
} else if (tabData.entries.length) {
|
} else if (tabData.entries.length) {
|
||||||
// Stash away the data we need for restoreDocument.
|
// Stash away the data we need for restoreDocument.
|
||||||
let activeIndex = tabData.index - 1;
|
|
||||||
this._restoringDocument = {
|
this._restoringDocument = {
|
||||||
entry: tabData.entries[activeIndex] || {},
|
|
||||||
formdata: tabData.formdata || {},
|
formdata: tabData.formdata || {},
|
||||||
scrollPositions: tabData.scroll || {},
|
scrollPositions: tabData.scroll || {},
|
||||||
};
|
};
|
||||||
|
@ -294,7 +284,7 @@ ContentRestoreInternal.prototype = {
|
||||||
*/
|
*/
|
||||||
restoreDocument() {
|
restoreDocument() {
|
||||||
if (!this._restoringDocument) {
|
if (!this._restoringDocument) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { formdata, scrollPositions } = this._restoringDocument;
|
let { formdata, scrollPositions } = this._restoringDocument;
|
||||||
|
@ -316,7 +306,6 @@ ContentRestoreInternal.prototype = {
|
||||||
SessionStoreUtils.restoreScrollPosition(frame, data);
|
SessionStoreUtils.restoreScrollPosition(frame, data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -99,16 +99,8 @@ class EventListener extends Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.contentRestoreInitialized) {
|
if (this.contentRestoreInitialized) {
|
||||||
// Restore the form data and scroll position (if we're restoring a
|
// Restore the form data and scroll position.
|
||||||
// document).
|
this.contentRestore.restoreDocument();
|
||||||
if (
|
|
||||||
this.contentRestore.restoreDocument() &&
|
|
||||||
Services.appinfo.sessionHistoryInParent
|
|
||||||
) {
|
|
||||||
this.mm.sendAsyncMessage("SessionStore:restoreTabContentComplete", {
|
|
||||||
epoch: this.store.epoch,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,7 +510,6 @@ const MESSAGES = [
|
||||||
"SessionStore:flush",
|
"SessionStore:flush",
|
||||||
"SessionStore:becomeActiveProcess",
|
"SessionStore:becomeActiveProcess",
|
||||||
"SessionStore:prepareForProcessChange",
|
"SessionStore:prepareForProcessChange",
|
||||||
"SessionStore:setRestoringDocument",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
class ContentSessionStore {
|
class ContentSessionStore {
|
||||||
|
@ -530,16 +521,17 @@ class ContentSessionStore {
|
||||||
|
|
||||||
this.contentRestoreInitialized = false;
|
this.contentRestoreInitialized = false;
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "contentRestore", () => {
|
this.handlers = [this.messageQueue];
|
||||||
this.contentRestoreInitialized = true;
|
|
||||||
return new ContentRestore(mm);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.handlers = [new EventListener(this), this.messageQueue];
|
|
||||||
if (Services.appinfo.sessionHistoryInParent) {
|
if (Services.appinfo.sessionHistoryInParent) {
|
||||||
this.mm.sendAsyncMessage("SessionStore:addSHistoryListener");
|
this.mm.sendAsyncMessage("SessionStore:addSHistoryListener");
|
||||||
} else {
|
} else {
|
||||||
|
this.handlers.push(new EventListener(this));
|
||||||
this.handlers.push(new SessionHistoryListener(this));
|
this.handlers.push(new SessionHistoryListener(this));
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "contentRestore", () => {
|
||||||
|
this.contentRestoreInitialized = true;
|
||||||
|
return new ContentRestore(mm);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MESSAGES.forEach(m => mm.addMessageListener(m, this));
|
MESSAGES.forEach(m => mm.addMessageListener(m, this));
|
||||||
|
@ -595,9 +587,6 @@ class ContentSessionStore {
|
||||||
// parent process.
|
// parent process.
|
||||||
this.mm.docShell.persistLayoutHistoryState();
|
this.mm.docShell.persistLayoutHistoryState();
|
||||||
break;
|
break;
|
||||||
case "SessionStore:setRestoringDocument":
|
|
||||||
this.contentRestore.setRestoringDocument(data);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
debug("received unknown message '" + name + "'");
|
debug("received unknown message '" + name + "'");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -527,6 +527,10 @@ var SessionStore = {
|
||||||
finishTabRemotenessChange(aTab, aSwitchId) {
|
finishTabRemotenessChange(aTab, aSwitchId) {
|
||||||
SessionStoreInternal.finishTabRemotenessChange(aTab, aSwitchId);
|
SessionStoreInternal.finishTabRemotenessChange(aTab, aSwitchId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
restoreTabContentComplete(aBrowser, aData) {
|
||||||
|
SessionStoreInternal._restoreTabContentComplete(aBrowser, aData);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Freeze the SessionStore object. We don't want anyone to modify it.
|
// Freeze the SessionStore object. We don't want anyone to modify it.
|
||||||
|
@ -1195,26 +1199,12 @@ var SessionStoreInternal = {
|
||||||
}
|
}
|
||||||
onStateChange(webProgress, request, stateFlags, status) {
|
onStateChange(webProgress, request, stateFlags, status) {
|
||||||
if (
|
if (
|
||||||
!webProgress.isTopLevel ||
|
webProgress.isTopLevel &&
|
||||||
!(stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
|
||||||
|
stateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||||
|
callbacks.onStopRequest
|
||||||
) {
|
) {
|
||||||
return;
|
callbacks.onStopRequest(request, this);
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
callbacks.onStartRequest &&
|
|
||||||
stateFlags & Ci.nsIWebProgressListener.STATE_START
|
|
||||||
) {
|
|
||||||
callbacks.onStartRequest();
|
|
||||||
this.uninstall();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
callbacks.onStopRequest &&
|
|
||||||
stateFlags & Ci.nsIWebProgressListener.STATE_STOP
|
|
||||||
) {
|
|
||||||
callbacks.onStopRequest();
|
|
||||||
this.uninstall();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1411,6 +1401,7 @@ var SessionStoreInternal = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aMessage.data.isFinal) {
|
if (aMessage.data.isFinal) {
|
||||||
// If this the final message we need to resolve all pending flush
|
// If this the final message we need to resolve all pending flush
|
||||||
// requests for the given browser as they might have been sent too
|
// requests for the given browser as they might have been sent too
|
||||||
|
@ -1421,7 +1412,6 @@ var SessionStoreInternal = {
|
||||||
for (let wm of [
|
for (let wm of [
|
||||||
this._browserSHistoryListener,
|
this._browserSHistoryListener,
|
||||||
this._browserSHistoryListenerForRestore,
|
this._browserSHistoryListenerForRestore,
|
||||||
this._browserProgressListenerForRestore,
|
|
||||||
]) {
|
]) {
|
||||||
let listener = wm.get(browser.permanentKey);
|
let listener = wm.get(browser.permanentKey);
|
||||||
if (listener) {
|
if (listener) {
|
||||||
|
@ -5641,6 +5631,15 @@ var SessionStoreInternal = {
|
||||||
_resetLocalTabRestoringState(aTab) {
|
_resetLocalTabRestoringState(aTab) {
|
||||||
let browser = aTab.linkedBrowser;
|
let browser = aTab.linkedBrowser;
|
||||||
|
|
||||||
|
if (Services.appinfo.sessionHistoryInParent) {
|
||||||
|
if (this._browserProgressListenerForRestore.has(browser.permanentKey)) {
|
||||||
|
this._browserProgressListenerForRestore
|
||||||
|
.get(browser.permanentKey)
|
||||||
|
.uninstall();
|
||||||
|
}
|
||||||
|
SessionStoreUtils.setRestoreData(browser.browsingContext, {});
|
||||||
|
}
|
||||||
|
|
||||||
// Keep the tab's previous state for later in this method
|
// Keep the tab's previous state for later in this method
|
||||||
let previousState = TAB_STATE_FOR_BROWSER.get(browser);
|
let previousState = TAB_STATE_FOR_BROWSER.get(browser);
|
||||||
|
|
||||||
|
@ -5674,7 +5673,9 @@ var SessionStoreInternal = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.messageManager.sendAsyncMessage("SessionStore:resetRestore", {});
|
if (!Services.appinfo.sessionHistoryInParent) {
|
||||||
|
browser.messageManager.sendAsyncMessage("SessionStore:resetRestore", {});
|
||||||
|
}
|
||||||
this._resetLocalTabRestoringState(tab);
|
this._resetLocalTabRestoringState(tab);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -5759,6 +5760,91 @@ var SessionStoreInternal = {
|
||||||
return deferred;
|
return deferred;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a single nsISessionStoreRestoreData tree for the provided |formdata|
|
||||||
|
* and |scroll| trees.
|
||||||
|
*/
|
||||||
|
buildRestoreData(formdata, scroll) {
|
||||||
|
function addFormEntries(root, fields, isXpath) {
|
||||||
|
for (let [key, value] of Object.entries(fields)) {
|
||||||
|
switch (typeof value) {
|
||||||
|
case "string":
|
||||||
|
root.addTextField(isXpath, key, value);
|
||||||
|
break;
|
||||||
|
case "boolean":
|
||||||
|
root.addCheckbox(isXpath, key, value);
|
||||||
|
break;
|
||||||
|
case "object": {
|
||||||
|
if (value === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
value.hasOwnProperty("type") &&
|
||||||
|
value.hasOwnProperty("fileList")
|
||||||
|
) {
|
||||||
|
root.addFileList(isXpath, key, value.type, value.fileList);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
value.hasOwnProperty("selectedIndex") &&
|
||||||
|
value.hasOwnProperty("value")
|
||||||
|
) {
|
||||||
|
root.addSingleSelect(
|
||||||
|
isXpath,
|
||||||
|
key,
|
||||||
|
value.selectedIndex,
|
||||||
|
value.value
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
key === "sessionData" &&
|
||||||
|
["about:sessionrestore", "about:welcomeback"].includes(
|
||||||
|
formdata.url
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
root.addTextField(isXpath, key, JSON.stringify(value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
root.addMultipleSelect(isXpath, key, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = SessionStoreUtils.constructSessionStoreRestoreData();
|
||||||
|
if (scroll?.hasOwnProperty("scroll")) {
|
||||||
|
root.scroll = scroll.scroll;
|
||||||
|
}
|
||||||
|
if (formdata?.hasOwnProperty("url")) {
|
||||||
|
root.url = formdata.url;
|
||||||
|
if (formdata.hasOwnProperty("innerHTML")) {
|
||||||
|
// eslint-disable-next-line no-unsanitized/property
|
||||||
|
root.innerHTML = formdata.innerHTML;
|
||||||
|
}
|
||||||
|
if (formdata.hasOwnProperty("xpath")) {
|
||||||
|
addFormEntries(root, formdata.xpath, /* isXpath */ true);
|
||||||
|
}
|
||||||
|
if (formdata.hasOwnProperty("id")) {
|
||||||
|
addFormEntries(root, formdata.id, /* isXpath */ false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let childrenLength = Math.max(
|
||||||
|
scroll?.children?.length || 0,
|
||||||
|
formdata?.children?.length || 0
|
||||||
|
);
|
||||||
|
for (let i = 0; i < childrenLength; i++) {
|
||||||
|
root.addChild(
|
||||||
|
this.buildRestoreData(formdata?.children?.[i], scroll?.children?.[i]),
|
||||||
|
i
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This mirrors ContentRestore.restoreHistory() for parent process session
|
* This mirrors ContentRestore.restoreHistory() for parent process session
|
||||||
* history restores, but we're not actually restoring history here.
|
* history restores, but we're not actually restoring history here.
|
||||||
|
@ -5823,18 +5909,14 @@ var SessionStoreInternal = {
|
||||||
throw new Error("This function should only be used with SHIP");
|
throw new Error("This function should only be used with SHIP");
|
||||||
}
|
}
|
||||||
|
|
||||||
let listener = this._browserProgressListenerForRestore.get(
|
for (let map of [
|
||||||
browser.permanentKey
|
this._browserProgressListenerForRestore,
|
||||||
);
|
this._browserSHistoryListenerForRestore,
|
||||||
if (listener) {
|
]) {
|
||||||
listener.uninstall();
|
let listener = map.get(browser.permanentKey);
|
||||||
}
|
if (listener) {
|
||||||
|
listener.uninstall();
|
||||||
listener = this._browserSHistoryListenerForRestore.get(
|
}
|
||||||
browser.permanentKey
|
|
||||||
);
|
|
||||||
if (listener) {
|
|
||||||
listener.uninstall();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let restoreData = {
|
let restoreData = {
|
||||||
|
@ -5846,43 +5928,56 @@ var SessionStoreInternal = {
|
||||||
this._restoreTabContentStarted(browser, restoreData);
|
this._restoreTabContentStarted(browser, restoreData);
|
||||||
|
|
||||||
let { tabData } = restoreData;
|
let { tabData } = restoreData;
|
||||||
|
let uri = null;
|
||||||
let uri = "about:blank";
|
let loadFlags = null;
|
||||||
let loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY;
|
|
||||||
|
|
||||||
if (tabData?.userTypedValue && tabData?.userTypedClear) {
|
if (tabData?.userTypedValue && tabData?.userTypedClear) {
|
||||||
uri = tabData.userTypedValue;
|
uri = tabData.userTypedValue;
|
||||||
loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||||
} else if (tabData?.entries.length) {
|
} else if (tabData?.entries.length) {
|
||||||
uri = loadFlags = null;
|
uri = tabData.entries[tabData.index - 1].url;
|
||||||
browser.messageManager.sendAsyncMessage(
|
let willRestoreContent = SessionStoreUtils.setRestoreData(
|
||||||
"SessionStore:setRestoringDocument",
|
browser.browsingContext,
|
||||||
{
|
this.buildRestoreData(tabData.formdata, tabData.scroll)
|
||||||
entry: tabData.entries[tabData.index - 1] || {},
|
|
||||||
formdata: tabData.formdata || {},
|
|
||||||
scrollPositions: tabData.scroll || {},
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
browser.browsingContext.sessionHistory.reloadCurrentEntry();
|
// We'll manually call RestoreTabContentComplete when the restore is done,
|
||||||
|
// so we only want to create the listener below if we're not restoring tab
|
||||||
|
// content.
|
||||||
|
if (willRestoreContent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uri = "about:blank";
|
||||||
|
loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri && loadFlags) {
|
if (uri) {
|
||||||
// We only create this listener if we're *not* expecting a reply from
|
|
||||||
// content. OTherwise we'll call _restoreTabContentComplete too early, and
|
|
||||||
// fire events before the restore has actually completed.
|
|
||||||
//
|
|
||||||
// XXX: If this causes problems, we may be able to just update tests that
|
|
||||||
// rely on the existing timing to wait for the load event instead.
|
|
||||||
this.addProgressListenerForRestore(browser, {
|
this.addProgressListenerForRestore(browser, {
|
||||||
onStopRequest: () => {
|
onStopRequest: (request, listener) => {
|
||||||
this._restoreTabContentComplete(browser, restoreData);
|
let requestURI = request.QueryInterface(Ci.nsIChannel)?.originalURI;
|
||||||
|
// FIXME: We sometimes see spurious STATE_STOP events for about:blank
|
||||||
|
// URIs, so we have to manually drop those here (unless we're actually
|
||||||
|
// expecting an about:blank load).
|
||||||
|
//
|
||||||
|
// In the case where we're firing _restoreTabContentComplete due to
|
||||||
|
// a normal load (i.e. !willRestoreContent), we could perhaps just not
|
||||||
|
// wait for the load here, and instead fix tests that depend on this
|
||||||
|
// behavior.
|
||||||
|
if (requestURI?.spec !== "about:blank" || uri === "about:blank") {
|
||||||
|
listener.uninstall();
|
||||||
|
this._restoreTabContentComplete(browser, restoreData);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.browsingContext.loadURI(uri, {
|
if (loadFlags) {
|
||||||
loadFlags,
|
browser.browsingContext.loadURI(uri, {
|
||||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
loadFlags,
|
||||||
});
|
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
browser.browsingContext.sessionHistory.reloadCurrentEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2683,8 +2683,8 @@ bool BrowsingContext::LegacyCheckOnlyOwningProcessCanSet(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BrowsingContext::LegacyRevertIfNotOwningOrParentProcess(ContentParent* aSource)
|
auto BrowsingContext::LegacyRevertIfNotOwningOrParentProcess(
|
||||||
-> CanSetResult {
|
ContentParent* aSource) -> CanSetResult {
|
||||||
if (aSource) {
|
if (aSource) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
|
||||||
|
@ -3168,6 +3168,11 @@ bool BrowsingContext::CanSet(FieldIndex<IDX_PendingInitialization>,
|
||||||
return IsTop() && GetPendingInitialization() && !aNewValue;
|
return IsTop() && GetPendingInitialization() && !aNewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BrowsingContext::CanSet(FieldIndex<IDX_HasRestoreData>, bool aNewValue,
|
||||||
|
ContentParent* aSource) {
|
||||||
|
return IsTop();
|
||||||
|
}
|
||||||
|
|
||||||
bool BrowsingContext::IsPopupAllowed() {
|
bool BrowsingContext::IsPopupAllowed() {
|
||||||
for (auto* context = GetCurrentWindowContext(); context;
|
for (auto* context = GetCurrentWindowContext(); context;
|
||||||
context = context->GetParentWindowContext()) {
|
context = context->GetParentWindowContext()) {
|
||||||
|
|
|
@ -198,7 +198,8 @@ enum class ExplicitActiveStatus : uint8_t {
|
||||||
/* The number of entries added to the session history because of this \
|
/* The number of entries added to the session history because of this \
|
||||||
* browsing context. */ \
|
* browsing context. */ \
|
||||||
FIELD(HistoryEntryCount, uint32_t) \
|
FIELD(HistoryEntryCount, uint32_t) \
|
||||||
FIELD(IsInBFCache, bool)
|
FIELD(IsInBFCache, bool) \
|
||||||
|
FIELD(HasRestoreData, bool)
|
||||||
|
|
||||||
// BrowsingContext, in this context, is the cross process replicated
|
// BrowsingContext, in this context, is the cross process replicated
|
||||||
// environment in which information about documents is stored. In
|
// environment in which information about documents is stored. In
|
||||||
|
@ -1027,6 +1028,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||||
ContentParent* aSource);
|
ContentParent* aSource);
|
||||||
void DidSet(FieldIndex<IDX_HasMainMediaController>, bool aOldValue);
|
void DidSet(FieldIndex<IDX_HasMainMediaController>, bool aOldValue);
|
||||||
|
|
||||||
|
bool CanSet(FieldIndex<IDX_HasRestoreData>, bool aNewValue,
|
||||||
|
ContentParent* aSource);
|
||||||
|
|
||||||
template <size_t I, typename T>
|
template <size_t I, typename T>
|
||||||
bool CanSet(FieldIndex<I>, const T&, ContentParent*) {
|
bool CanSet(FieldIndex<I>, const T&, ContentParent*) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/dom/EventTarget.h"
|
#include "mozilla/dom/EventTarget.h"
|
||||||
|
#include "mozilla/dom/PWindowGlobalParent.h"
|
||||||
#include "mozilla/dom/WindowGlobalParent.h"
|
#include "mozilla/dom/WindowGlobalParent.h"
|
||||||
#include "mozilla/dom/ContentProcessManager.h"
|
#include "mozilla/dom/ContentProcessManager.h"
|
||||||
#include "mozilla/dom/MediaController.h"
|
#include "mozilla/dom/MediaController.h"
|
||||||
|
@ -173,6 +174,14 @@ void CanonicalBrowsingContext::ReplacedBy(
|
||||||
}
|
}
|
||||||
aNewContext->mWebProgress = std::move(mWebProgress);
|
aNewContext->mWebProgress = std::move(mWebProgress);
|
||||||
|
|
||||||
|
mRequestedContentRestores = 0;
|
||||||
|
mCompletedContentRestores = 0;
|
||||||
|
SetRestoreData(nullptr);
|
||||||
|
|
||||||
|
aNewContext->mRestoreData = nullptr;
|
||||||
|
aNewContext->mRequestedContentRestores = 0;
|
||||||
|
aNewContext->mCompletedContentRestores = 0;
|
||||||
|
|
||||||
// Use the Transaction for the fields which need to be updated whether or not
|
// Use the Transaction for the fields which need to be updated whether or not
|
||||||
// the new context has been attached before.
|
// the new context has been attached before.
|
||||||
// SetWithoutSyncing can be used if context hasn't been attached.
|
// SetWithoutSyncing can be used if context hasn't been attached.
|
||||||
|
@ -180,6 +189,7 @@ void CanonicalBrowsingContext::ReplacedBy(
|
||||||
txn.SetBrowserId(GetBrowserId());
|
txn.SetBrowserId(GetBrowserId());
|
||||||
txn.SetHistoryID(GetHistoryID());
|
txn.SetHistoryID(GetHistoryID());
|
||||||
txn.SetExplicitActive(GetExplicitActive());
|
txn.SetExplicitActive(GetExplicitActive());
|
||||||
|
txn.SetHasRestoreData(false);
|
||||||
if (aNewContext->EverAttached()) {
|
if (aNewContext->EverAttached()) {
|
||||||
MOZ_ALWAYS_SUCCEEDS(txn.Commit(aNewContext));
|
MOZ_ALWAYS_SUCCEEDS(txn.Commit(aNewContext));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1721,6 +1731,56 @@ void CanonicalBrowsingContext::ResetScalingZoom() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CanonicalBrowsingContext::SetRestoreData(SessionStoreRestoreData* aData) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!mRestoreData || !aData,
|
||||||
|
"must either be clearing or initializing");
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
|
!aData || mCompletedContentRestores == mRequestedContentRestores,
|
||||||
|
"must not start restore in an unstable state");
|
||||||
|
mRestoreData = aData;
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(SetHasRestoreData(!!mRestoreData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanonicalBrowsingContext::RequestRestoreTabContent(
|
||||||
|
WindowGlobalParent* aWindow) {
|
||||||
|
if (!mRestoreData || mRestoreData->IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanonicalBrowsingContext* context = aWindow->GetBrowsingContext();
|
||||||
|
RefPtr<SessionStoreRestoreData> data = mRestoreData->FindChild(context);
|
||||||
|
|
||||||
|
// We'll only arrive here for a toplevel context after we've already sent
|
||||||
|
// down data for any out-of-process descendants, so it's fine to clear our
|
||||||
|
// data now.
|
||||||
|
if (context->IsTop()) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(context == this);
|
||||||
|
SetRestoreData(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && !data->IsEmpty()) {
|
||||||
|
auto onTabRestoreComplete = [self = RefPtr{this}](auto) {
|
||||||
|
self->mCompletedContentRestores++;
|
||||||
|
if (!self->mRestoreData &&
|
||||||
|
self->mCompletedContentRestores == self->mRequestedContentRestores) {
|
||||||
|
if (Element* browser = self->GetEmbedderElement()) {
|
||||||
|
SessionStoreUtils::CallRestoreTabContentComplete(browser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mRequestedContentRestores++;
|
||||||
|
|
||||||
|
if (aWindow->IsInProcess()) {
|
||||||
|
data->RestoreInto(context);
|
||||||
|
onTabRestoreComplete(true);
|
||||||
|
} else {
|
||||||
|
aWindow->SendRestoreTabContent(data, onTabRestoreComplete,
|
||||||
|
onTabRestoreComplete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CanonicalBrowsingContext::SetContainerFeaturePolicy(
|
void CanonicalBrowsingContext::SetContainerFeaturePolicy(
|
||||||
FeaturePolicy* aContainerFeaturePolicy) {
|
FeaturePolicy* aContainerFeaturePolicy) {
|
||||||
mContainerFeaturePolicy = aContainerFeaturePolicy;
|
mContainerFeaturePolicy = aContainerFeaturePolicy;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "mozilla/dom/BrowsingContext.h"
|
#include "mozilla/dom/BrowsingContext.h"
|
||||||
#include "mozilla/dom/MediaControlKeySource.h"
|
#include "mozilla/dom/MediaControlKeySource.h"
|
||||||
#include "mozilla/dom/BrowsingContextWebProgress.h"
|
#include "mozilla/dom/BrowsingContextWebProgress.h"
|
||||||
|
#include "mozilla/dom/SessionStoreRestoreData.h"
|
||||||
|
#include "mozilla/dom/SessionStoreUtils.h"
|
||||||
#include "mozilla/dom/ipc/IdType.h"
|
#include "mozilla/dom/ipc/IdType.h"
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "mozilla/MozPromise.h"
|
#include "mozilla/MozPromise.h"
|
||||||
|
@ -282,6 +284,9 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||||
return mContainerFeaturePolicy;
|
return mContainerFeaturePolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetRestoreData(SessionStoreRestoreData* aData);
|
||||||
|
void RequestRestoreTabContent(WindowGlobalParent* aWindow);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Called when the browsing context is being discarded.
|
// Called when the browsing context is being discarded.
|
||||||
void CanonicalDiscard();
|
void CanonicalDiscard();
|
||||||
|
@ -392,6 +397,10 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||||
RefPtr<nsBrowserStatusFilter> mStatusFilter;
|
RefPtr<nsBrowserStatusFilter> mStatusFilter;
|
||||||
|
|
||||||
RefPtr<FeaturePolicy> mContainerFeaturePolicy;
|
RefPtr<FeaturePolicy> mContainerFeaturePolicy;
|
||||||
|
|
||||||
|
RefPtr<SessionStoreRestoreData> mRestoreData;
|
||||||
|
uint32_t mRequestedContentRestores = 0;
|
||||||
|
uint32_t mCompletedContentRestores = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -5882,6 +5882,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
|
if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
|
||||||
nsCOMPtr<nsIWebProgress> webProgress =
|
nsCOMPtr<nsIWebProgress> webProgress =
|
||||||
do_QueryInterface(GetAsSupports(this));
|
do_QueryInterface(GetAsSupports(this));
|
||||||
|
@ -6528,6 +6529,12 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
|
||||||
//
|
//
|
||||||
nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
|
nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
|
||||||
|
|
||||||
|
// We'll never need to restore data into an about:blank document, so we can
|
||||||
|
// ignore those here.
|
||||||
|
if (!NS_IsAboutBlank(url)) {
|
||||||
|
MaybeRestoreTabContent();
|
||||||
|
}
|
||||||
|
|
||||||
// Notify the ContentViewer that the Document has finished loading. This
|
// Notify the ContentViewer that the Document has finished loading. This
|
||||||
// will cause any OnLoad(...) and PopState(...) handlers to fire.
|
// will cause any OnLoad(...) and PopState(...) handlers to fire.
|
||||||
if (!mEODForCurrentDocument && mContentViewer) {
|
if (!mEODForCurrentDocument && mContentViewer) {
|
||||||
|
@ -13271,6 +13278,23 @@ void nsDocShell::NotifyJSRunToCompletionStop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsDocShell::MaybeRestoreTabContent() {
|
||||||
|
BrowsingContext* bc = mBrowsingContext;
|
||||||
|
if (bc && bc->Top()->GetHasRestoreData()) {
|
||||||
|
if (XRE_IsParentProcess()) {
|
||||||
|
if (WindowGlobalParent* wgp = bc->Canonical()->GetCurrentWindowGlobal()) {
|
||||||
|
bc->Canonical()->RequestRestoreTabContent(wgp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (WindowContext* windowContext = bc->GetCurrentWindowContext()) {
|
||||||
|
if (WindowGlobalChild* wgc = windowContext->GetWindowGlobalChild()) {
|
||||||
|
wgc->SendRequestRestoreTabContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
|
void nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
|
||||||
const nsString& aKeyword) {
|
const nsString& aKeyword) {
|
||||||
|
|
|
@ -398,6 +398,8 @@ class nsDocShell final : public nsDocLoader,
|
||||||
|
|
||||||
void StoreWindowNameToSHEntries();
|
void StoreWindowNameToSHEntries();
|
||||||
|
|
||||||
|
void MaybeRestoreTabContent();
|
||||||
|
|
||||||
void SetWillChangeProcess() { mWillChangeProcess = true; }
|
void SetWillChangeProcess() { mWillChangeProcess = true; }
|
||||||
bool WillChangeProcess() { return mWillChangeProcess; }
|
bool WillChangeProcess() { return mWillChangeProcess; }
|
||||||
|
|
||||||
|
|
|
@ -1969,3 +1969,6 @@ addExternalIface('nsICookieJarSettings', nativeType='nsICookieJarSettings',
|
||||||
notflattened=True)
|
notflattened=True)
|
||||||
addExternalIface('nsIGleanPing', headerFile='mozilla/glean/bindings/Ping.h',
|
addExternalIface('nsIGleanPing', headerFile='mozilla/glean/bindings/Ping.h',
|
||||||
nativeType='nsIGleanPing', notflattened=True)
|
nativeType='nsIGleanPing', notflattened=True)
|
||||||
|
addExternalIface('nsISessionStoreRestoreData',
|
||||||
|
nativeType='nsISessionStoreRestoreData',
|
||||||
|
headerFile='nsISessionStoreRestoreData.h', notflattened=True)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
interface nsIDocShell;
|
interface nsIDocShell;
|
||||||
interface nsISupports;
|
interface nsISupports;
|
||||||
|
interface nsISessionStoreRestoreData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
|
* A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
|
||||||
|
@ -122,6 +123,11 @@ namespace SessionStoreUtils {
|
||||||
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
|
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
|
||||||
*/
|
*/
|
||||||
void restoreSessionStorage(nsIDocShell docShell, record<DOMString, record<DOMString, DOMString>> data);
|
void restoreSessionStorage(nsIDocShell docShell, record<DOMString, record<DOMString, DOMString>> data);
|
||||||
|
|
||||||
|
nsISessionStoreRestoreData constructSessionStoreRestoreData();
|
||||||
|
|
||||||
|
boolean setRestoreData(CanonicalBrowsingContext browsingContext,
|
||||||
|
nsISessionStoreRestoreData? data);
|
||||||
};
|
};
|
||||||
|
|
||||||
[GenerateConversionToJS, GenerateInit]
|
[GenerateConversionToJS, GenerateInit]
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
include "mozilla/dom/DocShellMessageUtils.h";
|
include "mozilla/dom/DocShellMessageUtils.h";
|
||||||
include "mozilla/dom/FeaturePolicyUtils.h";
|
include "mozilla/dom/FeaturePolicyUtils.h";
|
||||||
include "mozilla/dom/PermissionMessageUtils.h";
|
include "mozilla/dom/PermissionMessageUtils.h";
|
||||||
|
include "mozilla/dom/SessionStoreMessageUtils.h";
|
||||||
include "mozilla/ipc/TransportSecurityInfoUtils.h";
|
include "mozilla/ipc/TransportSecurityInfoUtils.h";
|
||||||
include "mozilla/ipc/URIUtils.h";
|
include "mozilla/ipc/URIUtils.h";
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h";
|
||||||
using mozilla::UseCounters from "mozilla/UseCounter.h";
|
using mozilla::UseCounters from "mozilla/UseCounter.h";
|
||||||
using mozilla::dom::MaybeDiscardedWindowContext from "mozilla/dom/WindowContext.h";
|
using mozilla::dom::MaybeDiscardedWindowContext from "mozilla/dom/WindowContext.h";
|
||||||
[RefCounted] using mozilla::dom::FeaturePolicy from "mozilla/dom/FeaturePolicy.h";
|
[RefCounted] using mozilla::dom::FeaturePolicy from "mozilla/dom/FeaturePolicy.h";
|
||||||
|
[RefCounted] using mozilla::dom::SessionStoreRestoreData from "mozilla/dom/SessionStoreRestoreData.h";
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
@ -90,6 +92,8 @@ child:
|
||||||
|
|
||||||
async SetContainerFeaturePolicy(FeaturePolicy aContainerFeaturePolicy);
|
async SetContainerFeaturePolicy(FeaturePolicy aContainerFeaturePolicy);
|
||||||
|
|
||||||
|
async RestoreTabContent(SessionStoreRestoreData aData) returns (bool success);
|
||||||
|
|
||||||
both:
|
both:
|
||||||
async RawMessage(JSActorMessageMeta aMetadata, ClonedMessageData? aData,
|
async RawMessage(JSActorMessageMeta aMetadata, ClonedMessageData? aData,
|
||||||
ClonedMessageData? aStack);
|
ClonedMessageData? aStack);
|
||||||
|
@ -169,6 +173,8 @@ parent:
|
||||||
*/
|
*/
|
||||||
async AccumulatePageUseCounters(UseCounters aUseCounters);
|
async AccumulatePageUseCounters(UseCounters aUseCounters);
|
||||||
|
|
||||||
|
async RequestRestoreTabContent();
|
||||||
|
|
||||||
async Destroy();
|
async Destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "mozilla/dom/BrowserBridgeChild.h"
|
#include "mozilla/dom/BrowserBridgeChild.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
|
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
|
||||||
|
#include "mozilla/dom/SessionStoreRestoreData.h"
|
||||||
#include "mozilla/dom/WindowGlobalActorsBinding.h"
|
#include "mozilla/dom/WindowGlobalActorsBinding.h"
|
||||||
#include "mozilla/dom/WindowGlobalParent.h"
|
#include "mozilla/dom/WindowGlobalParent.h"
|
||||||
#include "mozilla/dom/WindowContext.h"
|
#include "mozilla/dom/WindowContext.h"
|
||||||
|
@ -565,6 +566,13 @@ mozilla::ipc::IPCResult WindowGlobalChild::RecvSetContainerFeaturePolicy(
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult WindowGlobalChild::RecvRestoreTabContent(
|
||||||
|
dom::SessionStoreRestoreData* aData, RestoreTabContentResolver&& aResolve) {
|
||||||
|
aData->RestoreInto(BrowsingContext());
|
||||||
|
aResolve(true);
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
IPCResult WindowGlobalChild::RecvRawMessage(
|
IPCResult WindowGlobalChild::RecvRawMessage(
|
||||||
const JSActorMessageMeta& aMeta, const Maybe<ClonedMessageData>& aData,
|
const JSActorMessageMeta& aMeta, const Maybe<ClonedMessageData>& aData,
|
||||||
const Maybe<ClonedMessageData>& aStack) {
|
const Maybe<ClonedMessageData>& aStack) {
|
||||||
|
|
|
@ -170,6 +170,10 @@ class WindowGlobalChild final : public WindowGlobalActor,
|
||||||
mozilla::ipc::IPCResult RecvSetContainerFeaturePolicy(
|
mozilla::ipc::IPCResult RecvSetContainerFeaturePolicy(
|
||||||
dom::FeaturePolicy* aContainerFeaturePolicy);
|
dom::FeaturePolicy* aContainerFeaturePolicy);
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult RecvRestoreTabContent(
|
||||||
|
dom::SessionStoreRestoreData* aData,
|
||||||
|
RestoreTabContentResolver&& aResolve);
|
||||||
|
|
||||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1086,6 +1086,11 @@ void WindowGlobalParent::FinishAccumulatingPageUseCounters() {
|
||||||
mPageUseCounters = nullptr;
|
mPageUseCounters = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult WindowGlobalParent::RecvRequestRestoreTabContent() {
|
||||||
|
BrowsingContext()->Top()->RequestRestoreTabContent(this);
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
|
void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||||
if (mPageUseCountersWindow) {
|
if (mPageUseCountersWindow) {
|
||||||
mPageUseCountersWindow->FinishAccumulatingPageUseCounters();
|
mPageUseCountersWindow->FinishAccumulatingPageUseCounters();
|
||||||
|
|
|
@ -261,6 +261,8 @@ class WindowGlobalParent final : public WindowContext,
|
||||||
mozilla::ipc::IPCResult RecvAccumulatePageUseCounters(
|
mozilla::ipc::IPCResult RecvAccumulatePageUseCounters(
|
||||||
const UseCounters& aUseCounters);
|
const UseCounters& aUseCounters);
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult RecvRequestRestoreTabContent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WindowGlobalParent(CanonicalBrowsingContext* aBrowsingContext,
|
WindowGlobalParent(CanonicalBrowsingContext* aBrowsingContext,
|
||||||
uint64_t aInnerWindowId, uint64_t aOuterWindowId,
|
uint64_t aInnerWindowId, uint64_t aOuterWindowId,
|
||||||
|
|
|
@ -16,4 +16,6 @@ interface nsISessionStoreFunctions : nsISupports {
|
||||||
in Element aBrowser, in BrowsingContext aBrowsingContext,
|
in Element aBrowser, in BrowsingContext aBrowsingContext,
|
||||||
in uint32_t aFlushId, in boolean aIsFinal, in uint32_t aEpoch,
|
in uint32_t aFlushId, in boolean aIsFinal, in uint32_t aEpoch,
|
||||||
in jsval aData, in boolean aCollectSHistory);
|
in jsval aData, in boolean aCollectSHistory);
|
||||||
|
|
||||||
|
void RestoreTabContentComplete(in Element aBrowser);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
|
SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function RestoreTabContentComplete(aBrowser) {
|
||||||
|
SessionStore.restoreTabContentComplete(aBrowser, {});
|
||||||
|
}
|
||||||
|
|
||||||
function UpdateSessionStore(
|
function UpdateSessionStore(
|
||||||
aBrowser,
|
aBrowser,
|
||||||
aBrowsingContext,
|
aBrowsingContext,
|
||||||
|
@ -30,7 +34,7 @@ function UpdateSessionStore(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var EXPORTED_SYMBOLS = ["UpdateSessionStore"];
|
var EXPORTED_SYMBOLS = ["RestoreTabContentComplete", "UpdateSessionStore"];
|
||||||
|
|
||||||
var SessionStoreFuncInternal = {
|
var SessionStoreFuncInternal = {
|
||||||
// form data which is waiting to be updated
|
// form data which is waiting to be updated
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "ipc/IPCMessageUtils.h"
|
#include "ipc/IPCMessageUtils.h"
|
||||||
#include "SessionStoreData.h"
|
#include "SessionStoreData.h"
|
||||||
|
#include "SessionStoreUtils.h"
|
||||||
|
#include "SessionStoreRestoreData.h"
|
||||||
|
|
||||||
namespace IPC {
|
namespace IPC {
|
||||||
|
|
||||||
|
@ -68,4 +70,68 @@ struct ParamTraits<InputFormData> {
|
||||||
|
|
||||||
} // namespace IPC
|
} // namespace IPC
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct IPDLParamTraits<mozilla::dom::SessionStoreRestoreData*> {
|
||||||
|
// Note that we intentionally don't de/serialize mChildren here. The receiver
|
||||||
|
// won't be doing anything with the children lists, and it avoids sending form
|
||||||
|
// data for subframes to the content processes of their embedders.
|
||||||
|
|
||||||
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||||
|
mozilla::dom::SessionStoreRestoreData* aParam) {
|
||||||
|
bool isNull = !aParam;
|
||||||
|
WriteIPDLParam(aMsg, aActor, isNull);
|
||||||
|
if (isNull) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WriteIPDLParam(aMsg, aActor, aParam->mUrl);
|
||||||
|
WriteIPDLParam(aMsg, aActor, aParam->mInnerHTML);
|
||||||
|
WriteIPDLParam(aMsg, aActor, aParam->mScroll);
|
||||||
|
WriteIPDLParam(aMsg, aActor, aParam->mEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||||
|
IProtocol* aActor,
|
||||||
|
RefPtr<mozilla::dom::SessionStoreRestoreData>* aResult) {
|
||||||
|
*aResult = nullptr;
|
||||||
|
bool isNull;
|
||||||
|
if (!ReadIPDLParam(aMsg, aIter, aActor, &isNull)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isNull) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto data = MakeRefPtr<mozilla::dom::SessionStoreRestoreData>();
|
||||||
|
if (!ReadIPDLParam(aMsg, aIter, aActor, &data->mUrl) ||
|
||||||
|
!ReadIPDLParam(aMsg, aIter, aActor, &data->mInnerHTML) ||
|
||||||
|
!ReadIPDLParam(aMsg, aIter, aActor, &data->mScroll) ||
|
||||||
|
!ReadIPDLParam(aMsg, aIter, aActor, &data->mEntries)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*aResult = std::move(data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct IPDLParamTraits<mozilla::dom::SessionStoreRestoreData::Entry> {
|
||||||
|
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||||
|
mozilla::dom::SessionStoreRestoreData::Entry aParam) {
|
||||||
|
WriteIPDLParam(aMsg, aActor, aParam.mData);
|
||||||
|
WriteIPDLParam(aMsg, aActor, aParam.mIsXPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||||
|
IProtocol* aActor,
|
||||||
|
mozilla::dom::SessionStoreRestoreData::Entry* aResult) {
|
||||||
|
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mData) &&
|
||||||
|
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mIsXPath);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ipc
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // mozilla_dom_SessionStoreMessageUtils_h
|
#endif // mozilla_dom_SessionStoreMessageUtils_h
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
/* -*- 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/. */
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
#include "mozilla/dom/BrowsingContext.h"
|
||||||
|
#include "mozilla/dom/SessionStoreUtils.h"
|
||||||
|
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
|
||||||
|
#include "nsISessionStoreRestoreData.h"
|
||||||
|
|
||||||
|
bool SessionStoreRestoreData::IsEmpty() {
|
||||||
|
return (mUrl.IsEmpty() && mScroll.IsEmpty() && mInnerHTML.IsEmpty() &&
|
||||||
|
mEntries.IsEmpty() && mChildren.IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionStoreRestoreData* SessionStoreRestoreData::FindChild(
|
||||||
|
BrowsingContext* aContext) {
|
||||||
|
nsTArray<uint32_t> offsets;
|
||||||
|
for (const BrowsingContext* current = aContext;
|
||||||
|
current && current->GetParent(); current = current->GetParent()) {
|
||||||
|
// Don't bother continuing if any frame in our chain was created
|
||||||
|
// dynamically.
|
||||||
|
if (current->ChildOffset() < 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
offsets.AppendElement(current->ChildOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionStoreRestoreData* data = this;
|
||||||
|
|
||||||
|
for (uint32_t offset : Reversed(offsets)) {
|
||||||
|
if (!data || data->mChildren.Length() <= offset ||
|
||||||
|
!data->mChildren[offset] || data->mChildren[offset]->IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
data = data->mChildren[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
bool SessionStoreRestoreData::RestoreInto(RefPtr<BrowsingContext> aContext) {
|
||||||
|
if (!aContext->IsInProcess()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WindowContext* window = aContext->GetCurrentWindowContext()) {
|
||||||
|
if (!mScroll.IsEmpty()) {
|
||||||
|
if (nsGlobalWindowInner* inner = window->GetInnerWindow()) {
|
||||||
|
SessionStoreUtils::RestoreScrollPosition(*inner, mScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mUrl.IsEmpty()) {
|
||||||
|
if (nsCOMPtr<Document> doc = window->GetExtantDoc()) {
|
||||||
|
if (!SessionStoreUtils::RestoreFormData(*doc, mUrl, mInnerHTML,
|
||||||
|
mEntries)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionStoreRestoreData::AddFormEntry(
|
||||||
|
bool aIsXPath, const nsAString& aIdOrXPath,
|
||||||
|
sessionstore::FormEntryValue aValue) {
|
||||||
|
mEntries.AppendElement(
|
||||||
|
Entry{sessionstore::FormEntry{nsString(aIdOrXPath), aValue}, aIsXPath});
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(SessionStoreRestoreData, nsISessionStoreRestoreData,
|
||||||
|
SessionStoreRestoreData)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::GetUrl(nsACString& aUrl) {
|
||||||
|
aUrl = mUrl;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::SetUrl(const nsACString& aUrl) {
|
||||||
|
mUrl = aUrl;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::GetInnerHTML(nsAString& aInnerHTML) {
|
||||||
|
aInnerHTML = mInnerHTML;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::SetInnerHTML(const nsAString& aInnerHTML) {
|
||||||
|
mInnerHTML = aInnerHTML;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::GetScroll(nsACString& aScroll) {
|
||||||
|
aScroll = mScroll;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::SetScroll(const nsACString& aScroll) {
|
||||||
|
mScroll = aScroll;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::AddTextField(bool aIsXPath,
|
||||||
|
const nsAString& aIdOrXPath,
|
||||||
|
const nsAString& aValue) {
|
||||||
|
AddFormEntry(aIsXPath, aIdOrXPath, sessionstore::TextField{nsString(aValue)});
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::AddCheckbox(bool aIsXPath, const nsAString& aIdOrXPath,
|
||||||
|
const bool aValue) {
|
||||||
|
AddFormEntry(aIsXPath, aIdOrXPath, sessionstore::Checkbox{aValue});
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::AddFileList(bool aIsXPath, const nsAString& aIdOrXPath,
|
||||||
|
const nsAString& aType,
|
||||||
|
const nsTArray<nsString>& aFileList) {
|
||||||
|
AddFormEntry(aIsXPath, aIdOrXPath, sessionstore::FileList{aFileList});
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::AddSingleSelect(bool aIsXPath,
|
||||||
|
const nsAString& aIdOrXPath,
|
||||||
|
uint32_t aSelectedIndex,
|
||||||
|
const nsAString& aValue) {
|
||||||
|
AddFormEntry(aIsXPath, aIdOrXPath,
|
||||||
|
sessionstore::SingleSelect{aSelectedIndex, nsString(aValue)});
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::AddMultipleSelect(bool aIsXPath,
|
||||||
|
const nsAString& aIdOrXPath,
|
||||||
|
const nsTArray<nsString>& aValues) {
|
||||||
|
AddFormEntry(aIsXPath, aIdOrXPath, sessionstore::MultipleSelect{aValues});
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
SessionStoreRestoreData::AddChild(nsISessionStoreRestoreData* aChild,
|
||||||
|
uint32_t aIndex) {
|
||||||
|
if (nsCOMPtr<SessionStoreRestoreData> child = do_QueryInterface(aChild)) {
|
||||||
|
if (aIndex > mChildren.Length()) {
|
||||||
|
mChildren.SetLength(aIndex);
|
||||||
|
}
|
||||||
|
mChildren.InsertElementAt(aIndex, child);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||||
|
/* 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_SessionStoreRestoreData_h
|
||||||
|
#define mozilla_dom_SessionStoreRestoreData_h
|
||||||
|
|
||||||
|
#include "mozilla/Tuple.h"
|
||||||
|
#include "mozilla/dom/sessionstore/SessionStoreTypes.h"
|
||||||
|
#include "mozilla/dom/SessionStoreData.h"
|
||||||
|
#include "nsISessionStoreRestoreData.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
#define NS_SESSIONSTORERESTOREDATA_IID \
|
||||||
|
{ \
|
||||||
|
0x88800c5b, 0xe142, 0x4ac6, { \
|
||||||
|
0x91, 0x52, 0xca, 0xbd, 0x3b, 0x74, 0xb9, 0xf8 \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
class SessionStoreRestoreData final : public nsISessionStoreRestoreData {
|
||||||
|
public:
|
||||||
|
SessionStoreRestoreData() = default;
|
||||||
|
bool IsEmpty();
|
||||||
|
SessionStoreRestoreData* FindChild(BrowsingContext* aContext);
|
||||||
|
bool RestoreInto(RefPtr<BrowsingContext> aContext);
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSISESSIONSTORERESTOREDATA
|
||||||
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SESSIONSTORERESTOREDATA_IID)
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
sessionstore::FormEntry mData;
|
||||||
|
bool mIsXPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~SessionStoreRestoreData() = default;
|
||||||
|
void AddFormEntry(bool aIsXPath, const nsAString& aIdOrXPath,
|
||||||
|
sessionstore::FormEntryValue aValue);
|
||||||
|
|
||||||
|
nsCString mScroll;
|
||||||
|
nsCString mUrl;
|
||||||
|
nsString mInnerHTML;
|
||||||
|
nsTArray<Entry> mEntries;
|
||||||
|
nsTArray<RefPtr<SessionStoreRestoreData>> mChildren;
|
||||||
|
|
||||||
|
friend struct mozilla::ipc::IPDLParamTraits<SessionStoreRestoreData*>;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_DEFINE_STATIC_IID_ACCESSOR(SessionStoreRestoreData,
|
||||||
|
NS_SESSIONSTORERESTOREDATA_IID)
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif
|
|
@ -29,11 +29,13 @@
|
||||||
#include "nsIDocShell.h"
|
#include "nsIDocShell.h"
|
||||||
#include "nsIFormControl.h"
|
#include "nsIFormControl.h"
|
||||||
#include "nsIScrollableFrame.h"
|
#include "nsIScrollableFrame.h"
|
||||||
|
#include "nsISHistory.h"
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
|
using namespace mozilla::dom::sessionstore;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -274,11 +276,15 @@ static void CollectCurrentScrollPosition(JSContext* aCx, Document& aDocument,
|
||||||
void SessionStoreUtils::RestoreScrollPosition(const GlobalObject& aGlobal,
|
void SessionStoreUtils::RestoreScrollPosition(const GlobalObject& aGlobal,
|
||||||
nsGlobalWindowInner& aWindow,
|
nsGlobalWindowInner& aWindow,
|
||||||
const CollectedData& aData) {
|
const CollectedData& aData) {
|
||||||
if (!aData.mScroll.WasPassed()) {
|
if (aData.mScroll.WasPassed()) {
|
||||||
return;
|
RestoreScrollPosition(aWindow, aData.mScroll.Value());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsCCharSeparatedTokenizer tokenizer(aData.mScroll.Value(), ',');
|
/* static */
|
||||||
|
void SessionStoreUtils::RestoreScrollPosition(
|
||||||
|
nsGlobalWindowInner& aWindow, const nsCString& aScrollPosition) {
|
||||||
|
nsCCharSeparatedTokenizer tokenizer(aScrollPosition, ',');
|
||||||
nsAutoCString token(tokenizer.nextToken());
|
nsAutoCString token(tokenizer.nextToken());
|
||||||
int pos_X = atoi(token.get());
|
int pos_X = atoi(token.get());
|
||||||
token = tokenizer.nextToken();
|
token = tokenizer.nextToken();
|
||||||
|
@ -802,7 +808,6 @@ static void SetElementAsBool(Element* aElement, bool aValue) {
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
static void SetElementAsFiles(HTMLInputElement* aElement,
|
static void SetElementAsFiles(HTMLInputElement* aElement,
|
||||||
const CollectedFileListValue& aValue) {
|
const CollectedFileListValue& aValue) {
|
||||||
nsTArray<nsString> fileList;
|
|
||||||
IgnoredErrorResult rv;
|
IgnoredErrorResult rv;
|
||||||
aElement->MozSetFileNameArray(aValue.mFileList, rv);
|
aElement->MozSetFileNameArray(aValue.mFileList, rv);
|
||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
|
@ -927,7 +932,7 @@ static void SetElementAsObject(JSContext* aCx, Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
static void SetRestoreData(JSContext* aCx, Element* aElement,
|
static void SetSessionData(JSContext* aCx, Element* aElement,
|
||||||
JS::MutableHandle<JS::Value> aObject) {
|
JS::MutableHandle<JS::Value> aObject) {
|
||||||
nsAutoString data;
|
nsAutoString data;
|
||||||
if (nsContentUtils::StringifyJSON(aCx, aObject, data)) {
|
if (nsContentUtils::StringifyJSON(aCx, aObject, data)) {
|
||||||
|
@ -938,12 +943,11 @@ static void SetRestoreData(JSContext* aCx, Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
static void SetInnerHTML(Document& aDocument, const CollectedData& aData) {
|
static void SetInnerHTML(Document& aDocument, const nsString& aInnerHTML) {
|
||||||
RefPtr<Element> bodyElement = aDocument.GetBody();
|
RefPtr<Element> bodyElement = aDocument.GetBody();
|
||||||
if (aDocument.HasFlag(NODE_IS_EDITABLE) && bodyElement) {
|
if (aDocument.HasFlag(NODE_IS_EDITABLE) && bodyElement) {
|
||||||
IgnoredErrorResult rv;
|
IgnoredErrorResult rv;
|
||||||
bodyElement->SetInnerHTML(aData.mInnerHTML.Value(),
|
bodyElement->SetInnerHTML(aInnerHTML, aDocument.NodePrincipal(), rv);
|
||||||
aDocument.NodePrincipal(), rv);
|
|
||||||
if (!rv.Failed()) {
|
if (!rv.Failed()) {
|
||||||
nsContentUtils::DispatchInputEvent(bodyElement);
|
nsContentUtils::DispatchInputEvent(bodyElement);
|
||||||
}
|
}
|
||||||
|
@ -978,7 +982,7 @@ class FormDataParseContext : public txIParseContext {
|
||||||
bool mIsCaseInsensitive;
|
bool mIsCaseInsensitive;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Element* FindNodeByXPath(JSContext* aCx, Document& aDocument,
|
static Element* FindNodeByXPath(Document& aDocument,
|
||||||
const nsAString& aExpression) {
|
const nsAString& aExpression) {
|
||||||
FormDataParseContext parsingContext(aDocument.IsHTMLDocument());
|
FormDataParseContext parsingContext(aDocument.IsHTMLDocument());
|
||||||
IgnoredErrorResult rv;
|
IgnoredErrorResult rv;
|
||||||
|
@ -989,7 +993,7 @@ static Element* FindNodeByXPath(JSContext* aCx, Document& aDocument,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
RefPtr<XPathResult> result = expression->Evaluate(
|
RefPtr<XPathResult> result = expression->Evaluate(
|
||||||
aCx, aDocument, XPathResult::FIRST_ORDERED_NODE_TYPE, nullptr, rv);
|
aDocument, XPathResult::FIRST_ORDERED_NODE_TYPE, nullptr, rv);
|
||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1012,7 +1016,7 @@ bool SessionStoreUtils::RestoreFormData(const GlobalObject& aGlobal,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (aData.mInnerHTML.WasPassed()) {
|
if (aData.mInnerHTML.WasPassed()) {
|
||||||
SetInnerHTML(aDocument, aData);
|
SetInnerHTML(aDocument, aData.mInnerHTML.Value());
|
||||||
}
|
}
|
||||||
if (aData.mId.WasPassed()) {
|
if (aData.mId.WasPassed()) {
|
||||||
for (auto& entry : aData.mId.Value().Entries()) {
|
for (auto& entry : aData.mId.Value().Entries()) {
|
||||||
|
@ -1030,13 +1034,11 @@ bool SessionStoreUtils::RestoreFormData(const GlobalObject& aGlobal,
|
||||||
// cf. bug 467409
|
// cf. bug 467409
|
||||||
JSContext* cx = aGlobal.Context();
|
JSContext* cx = aGlobal.Context();
|
||||||
if (entry.mKey.EqualsLiteral("sessionData")) {
|
if (entry.mKey.EqualsLiteral("sessionData")) {
|
||||||
nsAutoCString url;
|
|
||||||
Unused << aDocument.GetDocumentURI()->GetSpecIgnoringRef(url);
|
|
||||||
if (url.EqualsLiteral("about:sessionrestore") ||
|
if (url.EqualsLiteral("about:sessionrestore") ||
|
||||||
url.EqualsLiteral("about:welcomeback")) {
|
url.EqualsLiteral("about:welcomeback")) {
|
||||||
JS::Rooted<JS::Value> object(
|
JS::Rooted<JS::Value> object(
|
||||||
cx, JS::ObjectValue(*entry.mValue.GetAsObject()));
|
cx, JS::ObjectValue(*entry.mValue.GetAsObject()));
|
||||||
SetRestoreData(cx, node, &object);
|
SetSessionData(cx, node, &object);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1048,8 +1050,7 @@ bool SessionStoreUtils::RestoreFormData(const GlobalObject& aGlobal,
|
||||||
}
|
}
|
||||||
if (aData.mXpath.WasPassed()) {
|
if (aData.mXpath.WasPassed()) {
|
||||||
for (auto& entry : aData.mXpath.Value().Entries()) {
|
for (auto& entry : aData.mXpath.Value().Entries()) {
|
||||||
RefPtr<Element> node =
|
RefPtr<Element> node = FindNodeByXPath(aDocument, entry.mKey);
|
||||||
FindNodeByXPath(aGlobal.Context(), aDocument, entry.mKey);
|
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1067,6 +1068,74 @@ bool SessionStoreUtils::RestoreFormData(const GlobalObject& aGlobal,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
void RestoreFormEntry(Element* aNode, FormEntryValue aValue) {
|
||||||
|
using Type = sessionstore::FormEntryValue::Type;
|
||||||
|
switch (aValue.type()) {
|
||||||
|
case Type::TCheckbox:
|
||||||
|
SetElementAsBool(aNode, aValue.get_Checkbox().value());
|
||||||
|
break;
|
||||||
|
case Type::TTextField:
|
||||||
|
SetElementAsString(aNode, aValue.get_TextField().value());
|
||||||
|
break;
|
||||||
|
case Type::TFileList: {
|
||||||
|
if (RefPtr<HTMLInputElement> input = HTMLInputElement::FromNode(aNode);
|
||||||
|
input && input->ControlType() == NS_FORM_INPUT_FILE) {
|
||||||
|
CollectedFileListValue value;
|
||||||
|
value.mFileList = std::move(aValue.get_FileList().valueList());
|
||||||
|
SetElementAsFiles(input, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::TSingleSelect:
|
||||||
|
case Type::TMultipleSelect: {
|
||||||
|
if (RefPtr<HTMLSelectElement> select =
|
||||||
|
HTMLSelectElement::FromNode(aNode)) {
|
||||||
|
if (!select->Multiple()) {
|
||||||
|
CollectedNonMultipleSelectValue value;
|
||||||
|
value.mSelectedIndex = aValue.get_SingleSelect().index();
|
||||||
|
value.mValue = aValue.get_SingleSelect().value();
|
||||||
|
SetElementAsSelect(select, value);
|
||||||
|
} else {
|
||||||
|
SetElementAsMultiSelect(select,
|
||||||
|
aValue.get_MultipleSelect().valueList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
/* static */
|
||||||
|
bool SessionStoreUtils::RestoreFormData(
|
||||||
|
Document& aDocument, const nsCString& aFormUrl, const nsString& aInnerHTML,
|
||||||
|
const nsTArray<SessionStoreRestoreData::Entry>& aEntries) {
|
||||||
|
// FIXME: Bug 1698878 - We should do this check in the parent instead.
|
||||||
|
nsAutoCString url;
|
||||||
|
Unused << aDocument.GetDocumentURI()->GetSpecIgnoringRef(url);
|
||||||
|
if (!aFormUrl.Equals(url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aInnerHTML.IsEmpty()) {
|
||||||
|
SetInnerHTML(aDocument, aInnerHTML);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : aEntries) {
|
||||||
|
RefPtr<Element> node = entry.mIsXPath
|
||||||
|
? FindNodeByXPath(aDocument, entry.mData.id())
|
||||||
|
: aDocument.GetElementById(entry.mData.id());
|
||||||
|
if (node) {
|
||||||
|
RestoreFormEntry(node, entry.mData.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read entries in the session storage data contained in a tab's history. */
|
/* Read entries in the session storage data contained in a tab's history. */
|
||||||
static void ReadAllEntriesFromStorage(nsPIDOMWindowOuter* aWindow,
|
static void ReadAllEntriesFromStorage(nsPIDOMWindowOuter* aWindow,
|
||||||
nsTArray<nsCString>& aOrigins,
|
nsTArray<nsCString>& aOrigins,
|
||||||
|
@ -1356,3 +1425,43 @@ static void CollectFrameTreeData(JSContext* aCx,
|
||||||
ret.mBoolVal.Construct(std::move(boolVal));
|
ret.mBoolVal.Construct(std::move(boolVal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
already_AddRefed<nsISessionStoreRestoreData>
|
||||||
|
SessionStoreUtils::ConstructSessionStoreRestoreData(
|
||||||
|
const GlobalObject& aGlobal) {
|
||||||
|
nsCOMPtr<nsISessionStoreRestoreData> data = new SessionStoreRestoreData();
|
||||||
|
return data.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
bool SessionStoreUtils::SetRestoreData(const GlobalObject& aGlobal,
|
||||||
|
CanonicalBrowsingContext& aContext,
|
||||||
|
nsISessionStoreRestoreData* aData) {
|
||||||
|
if (!mozilla::SessionHistoryInParent()) {
|
||||||
|
MOZ_CRASH("why were we called?");
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aContext.IsTop());
|
||||||
|
|
||||||
|
if (nsCOMPtr<SessionStoreRestoreData> data = do_QueryInterface(aData);
|
||||||
|
data && !data->IsEmpty()) {
|
||||||
|
aContext.SetRestoreData(data);
|
||||||
|
if (nsISHistory* shistory = aContext.GetSessionHistory()) {
|
||||||
|
shistory->ReloadCurrentEntry();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
nsresult SessionStoreUtils::CallRestoreTabContentComplete(Element* aBrowser) {
|
||||||
|
nsCOMPtr<nsISessionStoreFunctions> funcs =
|
||||||
|
do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");
|
||||||
|
NS_ENSURE_TRUE(funcs, NS_ERROR_FAILURE);
|
||||||
|
return funcs->RestoreTabContentComplete(aBrowser);
|
||||||
|
}
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
|
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||||
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
#include "mozilla/dom/SessionStoreUtilsBinding.h"
|
||||||
#include "SessionStoreData.h"
|
#include "SessionStoreData.h"
|
||||||
|
#include "SessionStoreRestoreData.h"
|
||||||
|
|
||||||
class nsIDocument;
|
class nsIDocument;
|
||||||
class nsGlobalWindowInner;
|
class nsGlobalWindowInner;
|
||||||
|
@ -55,6 +57,8 @@ class SessionStoreUtils {
|
||||||
static void RestoreScrollPosition(const GlobalObject& aGlobal,
|
static void RestoreScrollPosition(const GlobalObject& aGlobal,
|
||||||
nsGlobalWindowInner& aWindow,
|
nsGlobalWindowInner& aWindow,
|
||||||
const CollectedData& data);
|
const CollectedData& data);
|
||||||
|
static void RestoreScrollPosition(nsGlobalWindowInner& aWindow,
|
||||||
|
const nsCString& aScrollPosition);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@param aDocument: DOMDocument instance to obtain form data for.
|
@param aDocument: DOMDocument instance to obtain form data for.
|
||||||
|
@ -81,6 +85,10 @@ class SessionStoreUtils {
|
||||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||||
static bool RestoreFormData(const GlobalObject& aGlobal, Document& aDocument,
|
static bool RestoreFormData(const GlobalObject& aGlobal, Document& aDocument,
|
||||||
const CollectedData& aData);
|
const CollectedData& aData);
|
||||||
|
static bool RestoreFormData(
|
||||||
|
Document& aDocument, const nsCString& aFormUrl,
|
||||||
|
const nsString& aInnerHTML,
|
||||||
|
const nsTArray<SessionStoreRestoreData::Entry>& aEntries);
|
||||||
|
|
||||||
static void CollectedSessionStorage(BrowsingContext* aBrowsingContext,
|
static void CollectedSessionStorage(BrowsingContext* aBrowsingContext,
|
||||||
nsTArray<nsCString>& aOrigins,
|
nsTArray<nsCString>& aOrigins,
|
||||||
|
@ -93,6 +101,13 @@ class SessionStoreUtils {
|
||||||
|
|
||||||
static void ComposeInputData(const nsTArray<CollectedInputDataValue>& aData,
|
static void ComposeInputData(const nsTArray<CollectedInputDataValue>& aData,
|
||||||
InputElementData& ret);
|
InputElementData& ret);
|
||||||
|
|
||||||
|
static already_AddRefed<nsISessionStoreRestoreData>
|
||||||
|
ConstructSessionStoreRestoreData(const GlobalObject& aGlobal);
|
||||||
|
static bool SetRestoreData(const GlobalObject& aGlobal,
|
||||||
|
CanonicalBrowsingContext& aContext,
|
||||||
|
nsISessionStoreRestoreData* aData);
|
||||||
|
static nsresult CallRestoreTabContentComplete(Element* aBrowser);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -8,11 +8,13 @@ EXPORTS.mozilla.dom += [
|
||||||
"SessionStoreData.h",
|
"SessionStoreData.h",
|
||||||
"SessionStoreListener.h",
|
"SessionStoreListener.h",
|
||||||
"SessionStoreMessageUtils.h",
|
"SessionStoreMessageUtils.h",
|
||||||
|
"SessionStoreRestoreData.h",
|
||||||
"SessionStoreUtils.h",
|
"SessionStoreUtils.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
"SessionStoreListener.cpp",
|
"SessionStoreListener.cpp",
|
||||||
|
"SessionStoreRestoreData.cpp",
|
||||||
"SessionStoreUtils.cpp",
|
"SessionStoreUtils.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -20,9 +22,10 @@ EXTRA_JS_MODULES += [
|
||||||
"SessionStoreFunctions.jsm",
|
"SessionStoreFunctions.jsm",
|
||||||
]
|
]
|
||||||
|
|
||||||
XPIDL_MODULE = "sessionStore_funcs"
|
XPIDL_MODULE = "sessionstore"
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
XPIDL_SOURCES += [
|
||||||
|
"nsISessionStoreRestoreData.idl",
|
||||||
"SessionStoreFunctions.idl",
|
"SessionStoreFunctions.idl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||||
|
/* 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 "nsISupports.idl"
|
||||||
|
|
||||||
|
[scriptable, uuid(cd9f33c5-460d-4bbf-a459-f375ca9566d8)]
|
||||||
|
interface nsISessionStoreRestoreData : nsISupports {
|
||||||
|
// Setters for form data.
|
||||||
|
attribute AUTF8String url;
|
||||||
|
attribute AString innerHTML;
|
||||||
|
|
||||||
|
// Setters for scroll data.
|
||||||
|
attribute ACString scroll;
|
||||||
|
|
||||||
|
// Methods for adding individual form fields which are called as the JS code
|
||||||
|
// finds them.
|
||||||
|
void addTextField(in boolean aIsXPath, in AString aIdOrXPath,
|
||||||
|
in AString aValue);
|
||||||
|
void addCheckbox(in boolean aIsXPath, in AString aIdOrXPath,
|
||||||
|
in boolean aValue);
|
||||||
|
void addFileList(in boolean aIsXPath, in AString aIdOrXPath, in AString aType,
|
||||||
|
in Array<AString> aFileList);
|
||||||
|
void addSingleSelect(in boolean aIsXPath, in AString aIdOrXPath,
|
||||||
|
in unsigned long aSelectedIndex, in AString aValue);
|
||||||
|
void addMultipleSelect(in boolean aIsXPath, in AString aIdOrXPath,
|
||||||
|
in Array<AString> aValues);
|
||||||
|
|
||||||
|
// Add a child data object to our children list.
|
||||||
|
void addChild(in nsISessionStoreRestoreData aChild, in unsigned long aIndex);
|
||||||
|
};
|
Загрузка…
Ссылка в новой задаче