Bug 1544371 - Implement FormDataListener for contentSessionStore in C++ r=peterv

Differential Revision: https://phabricator.services.mozilla.com/D30078

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alphan Chen 2019-08-02 14:19:00 +00:00
Родитель 596c01a1db
Коммит efa34c0a06
14 изменённых файлов: 920 добавлений и 152 удалений

Просмотреть файл

@ -313,49 +313,6 @@ SessionHistoryListener.prototype.QueryInterface = ChromeUtils.generateQI([
Ci.nsISupportsWeakReference,
]);
/**
* Listens for changes to input elements. Whenever the value of an input
* element changes we will re-collect data for the current frame tree and send
* a message to the parent process.
*
* Causes a SessionStore:update message to be sent that contains the form data
* for all reachable frames.
*
* Example:
* {
* formdata: {url: "http://mozilla.org/", id: {input_id: "input value"}},
* children: [
* null,
* {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
* ]
* }
*/
class FormDataListener extends Handler {
constructor(store) {
super(store);
SessionStoreUtils.addDynamicFrameFilteredListener(
this.mm,
"input",
this,
true
);
this.stateChangeNotifier.addObserver(this);
}
handleEvent() {
this.messageQueue.push("formdata", () => this.collect());
}
onPageLoadStarted() {
this.messageQueue.push("formdata", () => null);
}
collect() {
return SessionStoreUtils.collectFormData(this.mm.content);
}
}
/**
* Listens for changes to the DOMSessionStorage. Whenever new keys are added,
* existing ones removed or changed, or the storage is cleared we will send a
@ -757,7 +714,6 @@ class ContentSessionStore {
this.handlers = [
new EventListener(this),
new FormDataListener(this),
new SessionHistoryListener(this),
new SessionStorageListener(this),
this.stateChangeNotifier,

Просмотреть файл

@ -160,9 +160,27 @@ dictionary CollectedData
sequence<object?> children;
};
dictionary InputElementData {
sequence<DOMString> id;
sequence<DOMString> type;
sequence<long> valueIdx;
sequence<long> selectedIndex;
sequence<DOMString> selectVal;
sequence<DOMString> strVal;
sequence<boolean> boolVal;
};
dictionary UpdateSessionStoreData {
ByteString docShellCaps;
boolean isPrivate;
sequence<ByteString> positions;
sequence<long> positionDescendants;
// The following are for input data
InputElementData id;
InputElementData xpath;
sequence<long> inputDescendants;
sequence<long> numId;
sequence<long> numXPath;
sequence<DOMString> innerHTML;
sequence<ByteString> url;
};

Просмотреть файл

@ -3787,9 +3787,15 @@ bool BrowserChild::UpdateSessionStore(uint32_t aFlushId, bool aIsFinal) {
store->GetScrollPositions(positions, positionDescendants);
}
Unused << SendSessionStoreUpdate(docShellCaps, privatedMode, positions,
positionDescendants, aFlushId, aIsFinal,
mSessionStoreListener->GetEpoch());
nsTArray<InputFormData> inputs;
nsTArray<CollectedInputDataValue> idVals, xPathVals;
if (store->IsFormDataChanged()) {
inputs = store->GetInputs(idVals, xPathVals);
}
Unused << SendSessionStoreUpdate(
docShellCaps, privatedMode, positions, positionDescendants, inputs,
idVals, xPathVals, aFlushId, aIsFinal, mSessionStoreListener->GetEpoch());
return true;
}

Просмотреть файл

@ -25,6 +25,7 @@
#include "mozilla/dom/RemoteDragStartData.h"
#include "mozilla/dom/RemoteWebProgress.h"
#include "mozilla/dom/RemoteWebProgressRequest.h"
#include "mozilla/dom/SessionStoreUtils.h"
#include "mozilla/dom/SessionStoreUtilsBinding.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/gfx/2D.h"
@ -2647,8 +2648,11 @@ void BrowserParent::ReconstructWebProgressAndRequest(
mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
const nsTArray<nsCString>&& aPositions,
const nsTArray<int32_t>&& aPositionDescendants, const uint32_t& aFlushId,
const bool& aIsFinal, const uint32_t& aEpoch) {
const nsTArray<int32_t>&& aPositionDescendants,
const nsTArray<InputFormData>& aInputs,
const nsTArray<CollectedInputDataValue>& aIdVals,
const nsTArray<CollectedInputDataValue>& aXPathVals,
const uint32_t& aFlushId, const bool& aIsFinal, const uint32_t& aEpoch) {
UpdateSessionStoreData data;
if (aDocShellCaps.isSome()) {
data.mDocShellCaps.Construct() = aDocShellCaps.value();
@ -2661,6 +2665,30 @@ mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
data.mPositionDescendants.Construct().Assign(
std::move(aPositionDescendants));
}
if (aIdVals.Length() != 0) {
SessionStoreUtils::ComposeInputData(aIdVals, data.mId.Construct());
}
if (aXPathVals.Length() != 0) {
SessionStoreUtils::ComposeInputData(aXPathVals, data.mXpath.Construct());
}
if (aInputs.Length() != 0) {
nsTArray<int> descendants, numId, numXPath;
nsTArray<nsString> innerHTML;
nsTArray<nsCString> url;
for (const InputFormData& input : aInputs) {
descendants.AppendElement(input.descendants);
numId.AppendElement(input.numId);
numXPath.AppendElement(input.numXPath);
innerHTML.AppendElement(input.innerHTML);
url.AppendElement(input.url);
}
data.mInputDescendants.Construct().Assign(std::move(descendants));
data.mNumId.Construct().Assign(std::move(numId));
data.mNumXPath.Construct().Assign(std::move(numXPath));
data.mInnerHTML.Construct().Assign(std::move(innerHTML));
data.mUrl.Construct().Assign(std::move(url));
}
nsCOMPtr<nsISessionStoreFunctions> funcs =
do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");

Просмотреть файл

@ -323,8 +323,11 @@ class BrowserParent final : public PBrowserParent,
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
const nsTArray<nsCString>&& aPositions,
const nsTArray<int32_t>&& aPositionDescendants, const uint32_t& aFlushId,
const bool& aIsFinal, const uint32_t& aEpoch);
const nsTArray<int32_t>&& aPositionDescendants,
const nsTArray<InputFormData>& aInputs,
const nsTArray<CollectedInputDataValue>& aIdVals,
const nsTArray<CollectedInputDataValue>& aXPathVals,
const uint32_t& aFlushId, const bool& aIsFinal, const uint32_t& aEpoch);
mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(
PBrowserParent* aOpener, const nsString& aURL, const nsString& aName,

Просмотреть файл

@ -88,6 +88,8 @@ using mozilla::dom::EffectsInfo from "mozilla/dom/TabMessageUtils.h";
using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
using mozilla::ScrollAxis from "mozilla/PresShellForwards.h";
using mozilla::ScrollFlags from "mozilla/PresShellForwards.h";
using struct InputFormData from "mozilla/dom/SessionStoreMessageUtils.h";
using struct CollectedInputDataValue from "mozilla/dom/SessionStoreMessageUtils.h";
namespace mozilla {
namespace dom {
@ -609,6 +611,8 @@ parent:
async SessionStoreUpdate(nsCString? aDocShellCaps, bool? aPrivatedMode,
nsCString[] aPositions, int32_t[] aPositionDescendants,
InputFormData[] aInputs, CollectedInputDataValue[] aIdVals,
CollectedInputDataValue[] aXPathVals,
uint32_t aFlushId, bool aIsFinal, uint32_t aEpoch);
child:

Просмотреть файл

@ -0,0 +1,61 @@
/* -*- Mode: C++; 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/. */
#ifndef mozilla_dom_SessionStoreData_h
#define mozilla_dom_SessionStoreData_h
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/dom/SessionStoreUtilsBinding.h"
#include "mozilla/Variant.h"
typedef mozilla::Variant<nsString, bool,
mozilla::dom::CollectedNonMultipleSelectValue,
nsTArray<nsString>>
InputDataValue;
/*
* Need two arrays based on this struct.
* One is for elements with id one is for XPath.
*
* id: id or XPath
* type: type of this input element
* bool: value is boolean
* string: value is nsString
* file: value is "arrayVal"
* singleSelect: value is "singleSelect"
* multipleSelect: value is "arrayVal"
*
* There are four value types:
* strVal: nsString
* boolVal: boolean
* singleSelect: single select value
* arrayVal: nsString array
*/
struct CollectedInputDataValue {
nsString id;
nsString type;
InputDataValue value;
CollectedInputDataValue() : value(false){};
};
/*
* Each index of the following array is corresponging to each frame.
* descendants: number of child frames of this frame
* innerHTML: innerHTML of this frame
* url: url of this frame
* numId: number of containing elements with id for this frame
* numXPath: number of containing elements with XPath for this frame
*/
struct InputFormData {
int32_t descendants;
nsString innerHTML;
nsCString url;
int32_t numId;
int32_t numXPath;
};
#endif /* mozilla_dom_SessionStoreData_h */

Просмотреть файл

@ -21,6 +21,259 @@ function UpdateSessionStore(aBrowser, aFlushId, aIsFinal, aEpoch, aData) {
var EXPORTED_SYMBOLS = ["UpdateSessionStore"];
var SessionStoreFuncInternal = {
// form data which is waiting to be updated
_formDataId: [],
_formDataIdValue: [],
_formDataXPath: [],
_formDataXPathValue: [],
/**
* The data will be stored in the arrays:
* "_formDataId, _formDataIdValue" for the elements with id.
* "_formDataXPath, _formDataXPathValue" for the elements with XPath.
*/
updateFormData: function SSF_updateFormData(aType, aData) {
let idArray = this._formDataId;
let valueArray = this._formDataIdValue;
if (aType == "XPath") {
idArray = this._formDataXPath;
valueArray = this._formDataXPathValue;
}
let valueIdx = aData.valueIdx;
for (let i = 0; i < aData.id.length; i++) {
idArray.push(aData.id[i]);
if (aData.type[i] == "singleSelect") {
valueArray.push({
selectedIndex: aData.selectedIndex[valueIdx[i]],
value: aData.selectVal[valueIdx[i]],
});
} else if (aData.type[i] == "file") {
valueArray.push({
type: "file",
fileList: aData.strVal.slice(valueIdx[i], valueIdx[++i]),
});
} else if (aData.type[i] == "multipleSelect") {
valueArray.push(aData.strVal.slice(valueIdx[i], valueIdx[++i]));
} else if (aData.type[i] == "string") {
valueArray.push(aData.strVal[valueIdx[i]]);
} else if (aData.type[i] == "bool") {
valueArray.push(aData.boolVal[valueIdx[i]]);
}
}
},
/**
* Return the array of formdata for this._sessionData.formdata.children
*
* aStartIndex: Current index for aInnerHTML/aUrl/aNumId/aNumXPath/aDescendants.
* (aStartIndex means the index of current root frame)
* aInnerHTML: Array for innerHTML.
* aUrl: Array for url.
* aNumId: Array for number of containing elements with id
* aNumXPath: Array for number of containing elements with XPath
* aDescendants: Array for number of descendants.
*
* aCurrentIdIdx: Current index for this._formDataId and this._formDataIdValue
* aCurrentXPathIdx: Current index for this._formDataXPath and this._formDataXPathValue
* aNumberOfDescendants: The number of descendants for current frame
*
* The returned array includes "aNumberOfDescendants" formdata objects.
*/
composeInputChildren: function SSF_composeInputChildren(
aInnerHTML,
aUrl,
aCurrentIdIdx,
aNumId,
aCurrentXpathIdx,
aNumXPath,
aDescendants,
aStartIndex,
aNumberOfDescendants
) {
let children = [];
let lastIndexOfNonNullbject = -1;
for (let i = 0; i < aNumberOfDescendants; i++) {
let currentIndex = aStartIndex + i;
let obj = {};
let objWithData = false;
// set url/id/xpath
if (aUrl[currentIndex]) {
obj.url = aUrl[currentIndex];
objWithData = true;
if (aInnerHTML[currentIndex]) {
// eslint-disable-next-line no-unsanitized/property
obj.innerHTML = aInnerHTML[currentIndex];
}
if (aNumId[currentIndex]) {
let idObj = {};
for (let idx = 0; idx < aNumId[currentIndex]; idx++) {
idObj[
this._formDataId[aCurrentIdIdx + idx]
] = this._formDataIdValue[aCurrentIdIdx + idx];
}
obj.id = idObj;
}
// 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
if (
obj.url == "about:sessionrestore" ||
obj.url == "about:welcomeback"
) {
obj.id.sessionData = JSON.parse(obj.id.sessionData);
}
if (aNumXPath[currentIndex]) {
let xpathObj = {};
for (let idx = 0; idx < aNumXPath[currentIndex]; idx++) {
xpathObj[
this._formDataXPath[aCurrentXpathIdx + idx]
] = this._formDataXPathValue[aCurrentXpathIdx + idx];
}
obj.xpath = xpathObj;
}
}
// compose the descendantsTree which will be pushed into children array
if (aDescendants[currentIndex]) {
let descendantsTree = this.composeInputChildren(
aInnerHTML,
aUrl,
aCurrentIdIdx + aNumId[currentIndex],
aNumId,
aCurrentXpathIdx + aNumXPath[currentIndex],
aNumXPath,
aDescendants,
currentIndex + 1,
aDescendants[currentIndex]
);
i += aDescendants[currentIndex];
if (descendantsTree) {
obj.children = descendantsTree;
}
}
if (objWithData) {
lastIndexOfNonNullbject = children.length;
children.push(obj);
} else {
children.push(null);
}
}
if (lastIndexOfNonNullbject == -1) {
return null;
}
return children.slice(0, lastIndexOfNonNullbject + 1);
},
/**
* Update the object for this._sessionData.formdata.
* The object contains the formdata for all reachable frames.
*
* "object.children" is an array with one entry per frame,
* containing formdata as a nested data structure according
* to the layout of the frame tree, or null if no formdata.
*
* Example:
* {
* url: "http://mozilla.org/",
* id: {input_id: "input value"},
* xpath: {input_xpath: "input value"},
* children: [
* null,
* {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
* ]
* }
*
* Each index of the following array is corresponging to each frame.
* aDescendants: Array for number of descendants
* aInnerHTML: Array for innerHTML
* aUrl: Array for url
* aNumId: Array for number of containing elements with id
* aNumXPath: Array for number of containing elements with XPath
*
* Here we use [index 0] to compose the formdata object of root frame.
* Besides, we use composeInputChildren() to get array of "object.children".
*/
updateInput: function SSF_updateInput(
aSessionData,
aDescendants,
aInnerHTML,
aUrl,
aNumId,
aNumXPath
) {
let obj = {};
let objWithData = false;
if (aUrl[0]) {
obj.url = aUrl[0];
if (aInnerHTML[0]) {
// eslint-disable-next-line no-unsanitized/property
obj.innerHTML = aInnerHTML[0];
objWithData = true;
}
if (aNumId[0]) {
let idObj = {};
for (let i = 0; i < aNumId[0]; i++) {
idObj[this._formDataId[i]] = this._formDataIdValue[i];
}
obj.id = idObj;
objWithData = true;
}
// 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
if (obj.url == "about:sessionrestore" || obj.url == "about:welcomeback") {
obj.id.sessionData = JSON.parse(obj.id.sessionData);
}
if (aNumXPath[0]) {
let xpathObj = {};
for (let i = 0; i < aNumXPath[0]; i++) {
xpathObj[this._formDataXPath[i]] = this._formDataXPathValue[i];
}
obj.xpath = xpathObj;
objWithData = true;
}
}
if (aDescendants.length > 1) {
let descendantsTree = this.composeInputChildren(
aInnerHTML,
aUrl,
aNumId[0],
aNumId,
aNumXPath[0],
aNumXPath,
aDescendants,
1,
aDescendants[0]
);
if (descendantsTree) {
obj.children = descendantsTree;
objWithData = true;
}
}
if (objWithData) {
aSessionData.formdata = obj;
} else {
aSessionData.formdata = null;
}
},
composeChildren: function SSF_composeScrollPositionsData(
aPositions,
aDescendants,
@ -119,11 +372,32 @@ var SessionStoreFuncInternal = {
aData.positionDescendants
);
}
if (aData.id != undefined) {
this.updateFormData("id", aData.id);
}
if (aData.xpath != undefined) {
this.updateFormData("XPath", aData.xpath);
}
if (aData.inputDescendants != undefined) {
this.updateInput(
currentData,
aData.inputDescendants,
aData.innerHTML,
aData.url,
aData.numId,
aData.numXPath
);
}
SessionStore.updateSessionStoreFromTablistener(aBrowser, {
data: currentData,
flushID: aFlushId,
isFinal: aIsFinal,
epoch: aEpoch,
});
this._formDataId = [];
this._formDataIdValue = [];
this._formDataXPath = [];
this._formDataXPathValue = [];
},
};

Просмотреть файл

@ -5,8 +5,10 @@
#include "mozilla/PresShell.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/SessionStoreListener.h"
#include "mozilla/dom/SessionStoreUtils.h"
#include "mozilla/dom/SessionStoreUtilsBinding.h"
#include "mozilla/dom/BrowserChild.h"
#include "nsGenericHTMLElement.h"
#include "nsIBrowser.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeOwner.h"
@ -39,6 +41,7 @@ ContentSessionStore::ContentSessionStore(nsIDocShell* aDocShell)
mPrivateChanged(false),
mIsPrivate(false),
mScrollChanged(NO_CHANGE),
mFormDataChanged(NO_CHANGE),
mDocCapChanged(false) {
MOZ_ASSERT(mDocShell);
// Check that value at startup as it might have
@ -98,6 +101,7 @@ bool ContentSessionStore::GetPrivateModeEnabled() {
void ContentSessionStore::OnDocumentStart() {
mScrollChanged = PAGELOADEDSTART;
mFormDataChanged = PAGELOADEDSTART;
nsCString caps = CollectDocShellCapabilities();
if (!mDocCaps.Equals(caps)) {
mDocCaps = caps;
@ -168,6 +172,7 @@ nsresult TabListener::Init() {
}
eventTarget->AddSystemEventListener(NS_LITERAL_STRING("mozvisualscroll"),
this, false);
eventTarget->AddSystemEventListener(NS_LITERAL_STRING("input"), this, false);
mEventListenerRegistered = true;
return NS_OK;
}
@ -285,6 +290,9 @@ TabListener::HandleEvent(Event* aEvent) {
if (eventType.EqualsLiteral("mozvisualscroll")) {
mSessionStore->SetScrollPositionChanged();
AddTimerForUpdate();
} else if (eventType.EqualsLiteral("input")) {
mSessionStore->SetFormDataChanged();
AddTimerForUpdate();
}
return NS_OK;
}
@ -394,11 +402,9 @@ int CollectPositions(BrowsingContext* aBrowsingContext,
int currentIdx = aPositions.Length() - 1;
/* Collect data from all child frame */
nsTArray<RefPtr<BrowsingContext>> children;
aBrowsingContext->GetChildren(children);
for (uint32_t i = 0; i < children.Length(); i++) {
for (auto& child : aBrowsingContext->GetChildren()) {
aPositionDescendants[currentIdx] +=
CollectPositions(children[i], aPositions, aPositionDescendants);
CollectPositions(child, aPositions, aPositionDescendants);
}
return aPositionDescendants[currentIdx] + 1;
@ -416,6 +422,103 @@ void ContentSessionStore::GetScrollPositions(
mScrollChanged = NO_CHANGE;
}
void CollectInput(Document& aDocument, InputFormData& aInput,
nsTArray<CollectedInputDataValue>& aIdVals,
nsTArray<CollectedInputDataValue>& aXPathVals) {
PresShell* presShell = aDocument.GetPresShell();
if (!presShell) {
return;
}
uint16_t numXPath = 0;
uint16_t numId = 0;
// textarea element
SessionStoreUtils::CollectFromTextAreaElement(aDocument, numXPath, numId,
aXPathVals, aIdVals);
// input element
SessionStoreUtils::CollectFromInputElement(aDocument, numXPath, numId,
aXPathVals, aIdVals);
// select element
SessionStoreUtils::CollectFromSelectElement(aDocument, numXPath, numId,
aXPathVals, aIdVals);
Element* bodyElement = aDocument.GetBody();
if (aDocument.HasFlag(NODE_IS_EDITABLE) && bodyElement) {
bodyElement->GetInnerHTML(aInput.innerHTML, IgnoreErrors());
}
if (aInput.innerHTML.IsEmpty() && numXPath == 0 && numId == 0) {
return;
}
// Store the frame's current URL with its form data so that we can compare
// it when restoring data to not inject form data into the wrong document.
nsIURI* uri = aDocument.GetDocumentURI();
if (uri) {
uri->GetSpecIgnoringRef(aInput.url);
}
aInput.numId = numId;
aInput.numXPath = numXPath;
}
int CollectInputs(BrowsingContext* aBrowsingContext,
nsTArray<InputFormData>& aInputs,
nsTArray<CollectedInputDataValue>& aIdVals,
nsTArray<CollectedInputDataValue>& aXPathVals) {
nsPIDOMWindowOuter* window = aBrowsingContext->GetDOMWindow();
if (!window) {
return 0;
}
nsIDocShell* docShell = window->GetDocShell();
if (!docShell || docShell->GetCreatedDynamically()) {
return 0;
}
Document* document = window->GetDoc();
if (!document) {
return 0;
}
/* Collect data from current frame */
InputFormData input;
input.descendants = 0;
input.numId = 0;
input.numXPath = 0;
CollectInput(*document, input, aIdVals, aXPathVals);
aInputs.AppendElement(input);
int currentIdx = aInputs.Length() - 1;
/* Collect data from all child frame */
for (auto& child : aBrowsingContext->GetChildren()) {
aInputs[currentIdx].descendants +=
CollectInputs(child, aInputs, aIdVals, aXPathVals);
}
return aInputs[currentIdx].descendants + 1;
}
nsTArray<InputFormData> ContentSessionStore::GetInputs(
nsTArray<CollectedInputDataValue>& aIdVals,
nsTArray<CollectedInputDataValue>& aXPathVals) {
nsTArray<InputFormData> inputs;
if (mFormDataChanged == PAGELOADEDSTART) {
mFormDataChanged = NO_CHANGE;
InputFormData input;
input.descendants = 0;
input.innerHTML = EmptyString();
input.url = EmptyCString();
input.numId = 0;
input.numXPath = 0;
inputs.AppendElement(input);
} else {
mFormDataChanged = NO_CHANGE;
CollectInputs(nsDocShell::Cast(mDocShell)->GetBrowsingContext(), inputs,
aIdVals, aXPathVals);
}
return inputs;
}
bool TabListener::ForceFlushFromParent(uint32_t aFlushId, bool aIsFinal) {
if (!XRE_IsParentProcess()) {
return false;
@ -474,6 +577,37 @@ bool TabListener::UpdateSessionStore(uint32_t aFlushId, bool aIsFinal) {
data.mPositions.Construct().Assign(std::move(positions));
data.mPositionDescendants.Construct().Assign(std::move(descendants));
}
if (mSessionStore->IsFormDataChanged()) {
nsTArray<CollectedInputDataValue> dataWithId, dataWithXpath;
nsTArray<InputFormData> inputs =
mSessionStore->GetInputs(dataWithId, dataWithXpath);
nsTArray<int> descendants, numId, numXPath;
nsTArray<nsString> innerHTML;
nsTArray<nsCString> url;
if (dataWithId.Length() != 0) {
SessionStoreUtils::ComposeInputData(dataWithId, data.mId.Construct());
}
if (dataWithXpath.Length() != 0) {
SessionStoreUtils::ComposeInputData(dataWithXpath,
data.mXpath.Construct());
}
for (const InputFormData& input : inputs) {
descendants.AppendElement(input.descendants);
numId.AppendElement(input.numId);
numXPath.AppendElement(input.numXPath);
innerHTML.AppendElement(input.innerHTML);
url.AppendElement(input.url);
}
if (descendants.Length() != 0) {
data.mInputDescendants.Construct().Assign(std::move(descendants));
data.mNumId.Construct().Assign(std::move(numId));
data.mNumXPath.Construct().Assign(std::move(numXPath));
data.mInnerHTML.Construct().Assign(std::move(innerHTML));
data.mUrl.Construct().Assign(std::move(url));
}
}
nsCOMPtr<nsISessionStoreFunctions> funcs =
do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");
@ -515,6 +649,8 @@ void TabListener::RemoveListeners() {
if (eventTarget) {
eventTarget->RemoveSystemEventListener(
NS_LITERAL_STRING("mozvisualscroll"), this, false);
eventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("input"), this,
false);
mEventListenerRegistered = false;
}
}

Просмотреть файл

@ -10,6 +10,7 @@
#include "nsIDOMEventListener.h"
#include "nsIPrivacyTransitionObserver.h"
#include "nsIWebProgressListener.h"
#include "SessionStoreData.h"
class nsITimer;
@ -31,10 +32,16 @@ class ContentSessionStore {
bool IsScrollPositionChanged() { return mScrollChanged != NO_CHANGE; }
void GetScrollPositions(nsTArray<nsCString>& aPositions,
nsTArray<int32_t>& aPositionDescendants);
void SetFormDataChanged() { mFormDataChanged = WITH_CHANGE; }
bool IsFormDataChanged() { return mFormDataChanged != NO_CHANGE; }
nsTArray<InputFormData> GetInputs(
nsTArray<CollectedInputDataValue>& aIdVals,
nsTArray<CollectedInputDataValue>& aXPathVals);
void OnDocumentStart();
void OnDocumentEnd();
bool UpdateNeeded() {
return mPrivateChanged || mDocCapChanged || IsScrollPositionChanged();
return mPrivateChanged || mDocCapChanged || IsScrollPositionChanged() ||
IsFormDataChanged();
}
private:
@ -48,7 +55,8 @@ class ContentSessionStore {
NO_CHANGE,
PAGELOADEDSTART, // set when the state of document is STATE_START
WITH_CHANGE, // set when the change event is observed
} mScrollChanged;
} mScrollChanged,
mFormDataChanged;
bool mDocCapChanged;
nsCString mDocCaps;
};

Просмотреть файл

@ -0,0 +1,71 @@
/* 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_SessionStoreMessageUtils_h
#define mozilla_dom_SessionStoreMessageUtils_h
#include "ipc/IPCMessageUtils.h"
#include "SessionStoreData.h"
namespace IPC {
template <>
struct ParamTraits<mozilla::dom::CollectedNonMultipleSelectValue> {
typedef mozilla::dom::CollectedNonMultipleSelectValue paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.mSelectedIndex);
WriteParam(aMsg, aParam.mValue);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->mSelectedIndex) &&
ReadParam(aMsg, aIter, &aResult->mValue);
}
};
template <>
struct ParamTraits<CollectedInputDataValue> {
typedef CollectedInputDataValue paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.id);
WriteParam(aMsg, aParam.type);
WriteParam(aMsg, aParam.value);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->id) &&
ReadParam(aMsg, aIter, &aResult->type) &&
ReadParam(aMsg, aIter, &aResult->value);
}
};
template <>
struct ParamTraits<InputFormData> {
typedef InputFormData paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.descendants);
WriteParam(aMsg, aParam.innerHTML);
WriteParam(aMsg, aParam.url);
WriteParam(aMsg, aParam.numId);
WriteParam(aMsg, aParam.numXPath);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->descendants) &&
ReadParam(aMsg, aIter, &aResult->innerHTML) &&
ReadParam(aMsg, aIter, &aResult->url) &&
ReadParam(aMsg, aIter, &aResult->numId) &&
ReadParam(aMsg, aIter, &aResult->numXPath);
}
};
} // namespace IPC
#endif // mozilla_dom_SessionStoreMessageUtils_h

Просмотреть файл

@ -375,15 +375,189 @@ AppendEntryToCollectedData(nsINode* aNode, const nsAString& aId,
return entry;
}
/*
@param aDocument: DOMDocument instance to obtain form data for.
@param aGeneratedCount: the current number of XPath expressions in the
returned object.
@return aRetVal: Form data encoded in an object.
*/
static void CollectFromTextAreaElement(Document& aDocument,
// A helper function to append a element into aXPathVals or aIdVals
static void AppendEntryToCollectedData(
nsINode* aNode, const nsAString& aId, CollectedInputDataValue& aEntry,
uint16_t& aNumXPath, uint16_t& aNumId,
nsTArray<CollectedInputDataValue>& aXPathVals,
nsTArray<CollectedInputDataValue>& aIdVals) {
if (!aId.IsEmpty()) {
aEntry.id = aId;
aIdVals.AppendElement(aEntry);
aNumId++;
} else {
nsAutoString xpath;
aNode->GenerateXPath(xpath);
aEntry.id = xpath;
aXPathVals.AppendElement(aEntry);
aNumXPath++;
}
}
/* for bool value */
static void AppendValueToCollectedData(nsINode* aNode, const nsAString& aId,
const bool& aValue,
uint16_t& aGeneratedCount,
JSContext* aCx,
Nullable<CollectedData>& aRetVal) {
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(aNode, aId, aGeneratedCount, aRetVal);
entry->mValue.SetAsBoolean() = aValue;
}
/* for bool value */
static void AppendValueToCollectedData(
nsINode* aNode, const nsAString& aId, const bool& aValue,
uint16_t& aNumXPath, uint16_t& aNumId,
nsTArray<CollectedInputDataValue>& aXPathVals,
nsTArray<CollectedInputDataValue>& aIdVals) {
CollectedInputDataValue entry;
entry.type = NS_LITERAL_STRING("bool");
entry.value = AsVariant(aValue);
AppendEntryToCollectedData(aNode, aId, entry, aNumXPath, aNumId, aXPathVals,
aIdVals);
}
/* for nsString value */
static void AppendValueToCollectedData(nsINode* aNode, const nsAString& aId,
const nsString& aValue,
uint16_t& aGeneratedCount,
Nullable<CollectedData>& aRetVal) {
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(aNode, aId, aGeneratedCount, aRetVal);
entry->mValue.SetAsString() = aValue;
}
/* for nsString value */
static void AppendValueToCollectedData(
nsINode* aNode, const nsAString& aId, const nsString& aValue,
uint16_t& aNumXPath, uint16_t& aNumId,
nsTArray<CollectedInputDataValue>& aXPathVals,
nsTArray<CollectedInputDataValue>& aIdVals) {
CollectedInputDataValue entry;
entry.type = NS_LITERAL_STRING("string");
entry.value = AsVariant(aValue);
AppendEntryToCollectedData(aNode, aId, entry, aNumXPath, aNumId, aXPathVals,
aIdVals);
}
/* for single select value */
static void AppendValueToCollectedData(
nsINode* aNode, const nsAString& aId,
const CollectedNonMultipleSelectValue& aValue, uint16_t& aGeneratedCount,
JSContext* aCx, Nullable<CollectedData>& aRetVal) {
JS::Rooted<JS::Value> jsval(aCx);
if (!ToJSValue(aCx, aValue, &jsval)) {
JS_ClearPendingException(aCx);
return;
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(aNode, aId, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
}
/* for single select value */
static void AppendValueToCollectedData(
nsINode* aNode, const nsAString& aId,
const CollectedNonMultipleSelectValue& aValue, uint16_t& aNumXPath,
uint16_t& aNumId, nsTArray<CollectedInputDataValue>& aXPathVals,
nsTArray<CollectedInputDataValue>& aIdVals) {
CollectedInputDataValue entry;
entry.type = NS_LITERAL_STRING("singleSelect");
entry.value = AsVariant(aValue);
AppendEntryToCollectedData(aNode, aId, entry, aNumXPath, aNumId, aXPathVals,
aIdVals);
}
/* special handing for input element with string type */
static void AppendValueToCollectedData(Document& aDocument, nsINode* aNode,
const nsAString& aId,
const nsString& aValue,
uint16_t& aGeneratedCount,
JSContext* aCx,
Nullable<CollectedData>& aRetVal) {
if (!aId.IsEmpty()) {
// 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
if (aId.EqualsLiteral("sessionData")) {
nsAutoCString url;
Unused << aDocument.GetDocumentURI()->GetSpecIgnoringRef(url);
if (url.EqualsLiteral("about:sessionrestore") ||
url.EqualsLiteral("about:welcomeback")) {
JS::Rooted<JS::Value> jsval(aCx);
if (JS_ParseJSON(aCx, aValue.get(), aValue.Length(), &jsval) &&
jsval.isObject()) {
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(aNode, aId, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
} else {
JS_ClearPendingException(aCx);
}
return;
}
}
}
AppendValueToCollectedData(aNode, aId, aValue, aGeneratedCount, aRetVal);
}
static void AppendValueToCollectedData(
Document& aDocument, nsINode* aNode, const nsAString& aId,
const nsString& aValue, uint16_t& aNumXPath, uint16_t& aNumId,
nsTArray<CollectedInputDataValue>& aXPathVals,
nsTArray<CollectedInputDataValue>& aIdVals) {
CollectedInputDataValue entry;
entry.type = NS_LITERAL_STRING("string");
entry.value = AsVariant(aValue);
AppendEntryToCollectedData(aNode, aId, entry, aNumXPath, aNumId, aXPathVals,
aIdVals);
}
/* for nsTArray<nsString>: file and multipleSelect */
static void AppendValueToCollectedData(nsINode* aNode, const nsAString& aId,
const nsAString& aValueType,
nsTArray<nsString>& aValue,
uint16_t& aGeneratedCount,
JSContext* aCx,
Nullable<CollectedData>& aRetVal) {
JS::Rooted<JS::Value> jsval(aCx);
if (aValueType.EqualsLiteral("file")) {
CollectedFileListValue val;
val.mType = aValueType;
val.mFileList.SwapElements(aValue);
if (!ToJSValue(aCx, val, &jsval)) {
JS_ClearPendingException(aCx);
return;
}
} else {
if (!ToJSValue(aCx, aValue, &jsval)) {
JS_ClearPendingException(aCx);
return;
}
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(aNode, aId, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
}
/* for nsTArray<nsString>: file and multipleSelect */
static void AppendValueToCollectedData(
nsINode* aNode, const nsAString& aId, const nsAString& aValueType,
const nsTArray<nsString>& aValue, uint16_t& aNumXPath, uint16_t& aNumId,
nsTArray<CollectedInputDataValue>& aXPathVals,
nsTArray<CollectedInputDataValue>& aIdVals) {
CollectedInputDataValue entry;
entry.type = aValueType;
entry.value = AsVariant(aValue);
AppendEntryToCollectedData(aNode, aId, entry, aNumXPath, aNumId, aXPathVals,
aIdVals);
}
/* static */
template <typename... ArgsT>
void SessionStoreUtils::CollectFromTextAreaElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args) {
RefPtr<nsContentList> textlist = NS_GetContentList(
&aDocument, kNameSpaceID_XHTML, NS_LITERAL_STRING("textarea"));
uint32_t length = textlist->Length(true);
@ -405,7 +579,7 @@ static void CollectFromTextAreaElement(Document& aDocument,
if (id.IsEmpty() && (aGeneratedCount > kMaxTraversedXPaths)) {
continue;
}
nsAutoString value;
nsString value;
textArea->GetValue(value);
// In order to reduce XPath generation (which is slow), we only save data
// for form fields that have been changed. (cf. bug 537289)
@ -413,21 +587,16 @@ static void CollectFromTextAreaElement(Document& aDocument,
eCaseMatters)) {
continue;
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(textArea, id, aGeneratedCount, aRetVal);
entry->mValue.SetAsString() = value;
AppendValueToCollectedData(textArea, id, value, aGeneratedCount,
std::forward<ArgsT>(args)...);
}
}
/*
@param aDocument: DOMDocument instance to obtain form data for.
@param aGeneratedCount: the current number of XPath expressions in the
returned object.
@return aRetVal: Form data encoded in an object.
*/
static void CollectFromInputElement(JSContext* aCx, Document& aDocument,
uint16_t& aGeneratedCount,
Nullable<CollectedData>& aRetVal) {
/* static */
template <typename... ArgsT>
void SessionStoreUtils::CollectFromInputElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args) {
RefPtr<nsContentList> inputlist = NS_GetContentList(
&aDocument, kNameSpaceID_XHTML, NS_LITERAL_STRING("input"));
uint32_t length = inputlist->Length(true);
@ -461,16 +630,15 @@ static void CollectFromInputElement(JSContext* aCx, Document& aDocument,
if (!aInfo.IsNull() && !aInfo.Value().mCanAutomaticallyPersist) {
continue;
}
nsAutoString value;
if (input->ControlType() == NS_FORM_INPUT_CHECKBOX ||
input->ControlType() == NS_FORM_INPUT_RADIO) {
bool checked = input->Checked();
if (checked == input->DefaultChecked()) {
continue;
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(input, id, aGeneratedCount, aRetVal);
entry->mValue.SetAsBoolean() = checked;
AppendValueToCollectedData(input, id, checked, aGeneratedCount,
std::forward<ArgsT>(args)...);
} else if (input->ControlType() == NS_FORM_INPUT_FILE) {
IgnoredErrorResult rv;
nsTArray<nsString> result;
@ -478,19 +646,10 @@ static void CollectFromInputElement(JSContext* aCx, Document& aDocument,
if (rv.Failed() || result.Length() == 0) {
continue;
}
CollectedFileListValue val;
val.mType = NS_LITERAL_STRING("file");
val.mFileList.SwapElements(result);
JS::Rooted<JS::Value> jsval(aCx);
if (!ToJSValue(aCx, val, &jsval)) {
JS_ClearPendingException(aCx);
continue;
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(input, id, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
AppendValueToCollectedData(input, id, NS_LITERAL_STRING("file"), result,
aGeneratedCount, std::forward<ArgsT>(args)...);
} else {
nsString value;
input->GetValue(value, CallerType::System);
// In order to reduce XPath generation (which is slow), we only save data
// for form fields that have been changed. (cf. bug 537289)
@ -501,45 +660,17 @@ static void CollectFromInputElement(JSContext* aCx, Document& aDocument,
eCaseMatters)) {
continue;
}
if (!id.IsEmpty()) {
// 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
if (id.EqualsLiteral("sessionData")) {
nsAutoCString url;
Unused << aDocument.GetDocumentURI()->GetSpecIgnoringRef(url);
if (url.EqualsLiteral("about:sessionrestore") ||
url.EqualsLiteral("about:welcomeback")) {
JS::Rooted<JS::Value> jsval(aCx);
if (JS_ParseJSON(aCx, value.get(), value.Length(), &jsval) &&
jsval.isObject()) {
Record<nsString, OwningStringOrBooleanOrObject>::EntryType*
entry = AppendEntryToCollectedData(input, id, aGeneratedCount,
aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
} else {
JS_ClearPendingException(aCx);
}
continue;
}
}
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(input, id, aGeneratedCount, aRetVal);
entry->mValue.SetAsString() = value;
AppendValueToCollectedData(aDocument, input, id, value, aGeneratedCount,
std::forward<ArgsT>(args)...);
}
}
}
/*
@param aDocument: DOMDocument instance to obtain form data for.
@param aGeneratedCount: the current number of XPath expressions in the
returned object.
@return aRetVal: Form data encoded in an object.
*/
static void CollectFromSelectElement(JSContext* aCx, Document& aDocument,
uint16_t& aGeneratedCount,
Nullable<CollectedData>& aRetVal) {
/* static */
template <typename... ArgsT>
void SessionStoreUtils::CollectFromSelectElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args) {
RefPtr<nsContentList> selectlist = NS_GetContentList(
&aDocument, kNameSpaceID_XHTML, NS_LITERAL_STRING("select"));
uint32_t length = selectlist->Length(true);
@ -569,15 +700,8 @@ static void CollectFromSelectElement(JSContext* aCx, Document& aDocument,
CollectedNonMultipleSelectValue val;
val.mSelectedIndex = select->SelectedIndex();
val.mValue = selectVal.AsAString();
JS::Rooted<JS::Value> jsval(aCx);
if (!ToJSValue(aCx, val, &jsval)) {
JS_ClearPendingException(aCx);
continue;
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(select, id, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
AppendValueToCollectedData(select, id, val, aGeneratedCount,
std::forward<ArgsT>(args)...);
} else {
// <select>s with the multiple attribute are easier to determine the
// default value since each <option> has a defaultSelected property
@ -603,14 +727,10 @@ static void CollectFromSelectElement(JSContext* aCx, Document& aDocument,
if (hasDefaultValue) {
continue;
}
JS::Rooted<JS::Value> jsval(aCx);
if (!ToJSValue(aCx, selectslist, &jsval)) {
JS_ClearPendingException(aCx);
continue;
}
Record<nsString, OwningStringOrBooleanOrObject>::EntryType* entry =
AppendEntryToCollectedData(select, id, aGeneratedCount, aRetVal);
entry->mValue.SetAsObject() = &jsval.toObject();
AppendValueToCollectedData(
select, id, NS_LITERAL_STRING("multipleSelect"), selectslist,
aGeneratedCount, std::forward<ArgsT>(args)...);
}
}
}
@ -619,11 +739,14 @@ static void CollectCurrentFormData(JSContext* aCx, Document& aDocument,
Nullable<CollectedData>& aRetVal) {
uint16_t generatedCount = 0;
/* textarea element */
CollectFromTextAreaElement(aDocument, generatedCount, aRetVal);
SessionStoreUtils::CollectFromTextAreaElement(aDocument, generatedCount,
aRetVal);
/* input element */
CollectFromInputElement(aCx, aDocument, generatedCount, aRetVal);
SessionStoreUtils::CollectFromInputElement(aDocument, generatedCount, aCx,
aRetVal);
/* select element */
CollectFromSelectElement(aCx, aDocument, generatedCount, aRetVal);
SessionStoreUtils::CollectFromSelectElement(aDocument, generatedCount, aCx,
aRetVal);
Element* bodyElement = aDocument.GetBody();
if (aDocument.HasFlag(NODE_IS_EDITABLE) && bodyElement) {
@ -1168,11 +1291,9 @@ static void CollectFrameTreeData(JSContext* aCx,
SequenceRooter<JSObject*> rooter(aCx, &childrenData);
uint32_t trailingNullCounter = 0;
nsTArray<RefPtr<BrowsingContext>> children;
aBrowsingContext->GetChildren(children);
for (uint32_t i = 0; i < children.Length(); i++) {
for (auto& child : aBrowsingContext->GetChildren()) {
NullableRootedDictionary<CollectedData> data(aCx);
CollectFrameTreeData(aCx, children[i], data, aFunc);
CollectFrameTreeData(aCx, child, data, aFunc);
if (data.IsNull()) {
childrenData.AppendElement(nullptr);
trailingNullCounter++;
@ -1206,3 +1327,61 @@ static void CollectFrameTreeData(JSContext* aCx,
CollectFrameTreeData(aGlobal.Context(), aWindow.get(), aRetVal,
CollectCurrentFormData);
}
/* static */ void SessionStoreUtils::ComposeInputData(
const nsTArray<CollectedInputDataValue>& aData, InputElementData& ret) {
nsTArray<int> selectedIndex, valueIdx;
nsTArray<nsString> id, selectVal, strVal, type;
nsTArray<bool> boolVal;
for (const CollectedInputDataValue& data : aData) {
id.AppendElement(data.id);
type.AppendElement(data.type);
if (data.value.is<mozilla::dom::CollectedNonMultipleSelectValue>()) {
valueIdx.AppendElement(selectVal.Length());
selectedIndex.AppendElement(
data.value.as<mozilla::dom::CollectedNonMultipleSelectValue>()
.mSelectedIndex);
selectVal.AppendElement(
data.value.as<mozilla::dom::CollectedNonMultipleSelectValue>()
.mValue);
} else if (data.value.is<nsTArray<nsString>>()) {
// The first valueIdx is "index of the first string value"
valueIdx.AppendElement(strVal.Length());
strVal.AppendElements(data.value.as<nsTArray<nsString>>());
// The second valueIdx is "index of the last string value" + 1
id.AppendElement(data.id);
type.AppendElement(data.type);
valueIdx.AppendElement(strVal.Length());
} else if (data.value.is<nsString>()) {
valueIdx.AppendElement(strVal.Length());
strVal.AppendElement(data.value.as<nsString>());
} else if (data.type.EqualsLiteral("bool")) {
valueIdx.AppendElement(boolVal.Length());
boolVal.AppendElement(data.value.as<bool>());
}
}
if (selectedIndex.Length() != 0) {
ret.mSelectedIndex.Construct().Assign(std::move(selectedIndex));
}
if (valueIdx.Length() != 0) {
ret.mValueIdx.Construct().Assign(std::move(valueIdx));
}
if (id.Length() != 0) {
ret.mId.Construct().Assign(std::move(id));
}
if (selectVal.Length() != 0) {
ret.mSelectVal.Construct().Assign(std::move(selectVal));
}
if (strVal.Length() != 0) {
ret.mStrVal.Construct().Assign(std::move(strVal));
}
if (type.Length() != 0) {
ret.mType.Construct().Assign(std::move(type));
}
if (boolVal.Length() != 0) {
ret.mBoolVal.Construct().Assign(std::move(boolVal));
}
}

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/SessionStoreUtilsBinding.h"
#include "SessionStoreData.h"
class nsIDocument;
class nsGlobalWindowInner;
@ -54,6 +55,24 @@ class SessionStoreUtils {
nsGlobalWindowInner& aWindow,
const CollectedData& data);
/*
@param aDocument: DOMDocument instance to obtain form data for.
@param aGeneratedCount: the current number of XPath expressions in the
returned object.
*/
template <typename... ArgsT>
static void CollectFromTextAreaElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args);
template <typename... ArgsT>
static void CollectFromInputElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args);
template <typename... ArgsT>
static void CollectFromSelectElement(Document& aDocument,
uint16_t& aGeneratedCount,
ArgsT&&... args);
static void CollectFormData(const GlobalObject& aGlobal,
WindowProxyHolder& aWindow,
Nullable<CollectedData>& aRetVal);
@ -69,6 +88,9 @@ class SessionStoreUtils {
static void RestoreSessionStorage(
const GlobalObject& aGlobal, nsIDocShell* aDocShell,
const Record<nsString, Record<nsString, nsString>>& aData);
static void ComposeInputData(const nsTArray<CollectedInputDataValue>& aData,
InputElementData& ret);
};
} // namespace dom

Просмотреть файл

@ -5,7 +5,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'SessionStoreData.h',
'SessionStoreListener.h',
'SessionStoreMessageUtils.h',
'SessionStoreUtils.h',
]