blob: b7df2d4dc79248b3792938ff485dd1a0e6d70829 [file] [log] [blame]
tkent@chromium.org34554872012-06-08 09:53:52 +00001/*
2 * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "FormController.h"
23
tkent@chromium.orgb53db042012-06-28 08:48:20 +000024#include "HTMLFormElement.h"
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +000025#include "HTMLInputElement.h"
tkent@chromium.orgb53db042012-06-28 08:48:20 +000026#include <wtf/text/StringBuilder.h>
tkent@chromium.org34554872012-06-08 09:53:52 +000027
28namespace WebCore {
29
30using namespace HTMLNames;
31
tkent@chromium.org03055db2012-07-13 10:59:59 +000032static inline HTMLFormElement* ownerFormForState(const HTMLFormControlElementWithState& control)
33{
34 // Assume controls with form attribute have no owners because we restore
35 // state during parsing and form owners of such controls might be
36 // indeterminate.
37 return control.fastHasAttribute(formAttr) ? 0 : control.form();
38}
39
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000040// ----------------------------------------------------------------------------
41
42// Serilized form of FormControlState:
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000043// (',' means strings around it are separated in stateVector.)
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000044//
tkent@chromium.org98085312012-06-22 05:36:28 +000045// SerializedControlState ::= SkipState | RestoreState
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000046// SkipState ::= '0'
47// RestoreState ::= UnsignedNumber, ControlValue+
48// UnsignedNumber ::= [0-9]+
49// ControlValue ::= arbitrary string
50//
51// RestoreState has a sequence of ControlValues. The length of the
52// sequence is represented by UnsignedNumber.
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000053
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000054void FormControlState::serializeTo(Vector<String>& stateVector) const
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000055{
56 ASSERT(!isFailure());
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000057 stateVector.append(String::number(m_values.size()));
tkent@chromium.org98085312012-06-22 05:36:28 +000058 for (size_t i = 0; i < m_values.size(); ++i)
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000059 stateVector.append(m_values[i].isNull() ? emptyString() : m_values[i]);
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000060}
61
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000062FormControlState FormControlState::deserialize(const Vector<String>& stateVector, size_t& index)
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000063{
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000064 if (index >= stateVector.size())
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000065 return FormControlState(TypeFailure);
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000066 size_t valueSize = stateVector[index++].toUInt();
67 if (!valueSize)
68 return FormControlState();
69 if (index + valueSize > stateVector.size())
70 return FormControlState(TypeFailure);
tkent@chromium.org98085312012-06-22 05:36:28 +000071 FormControlState state;
72 state.m_values.reserveCapacity(valueSize);
tkent@chromium.orgb5f15632012-06-26 01:20:05 +000073 for (size_t i = 0; i < valueSize; ++i)
74 state.append(stateVector[index++]);
tkent@chromium.org98085312012-06-22 05:36:28 +000075 return state;
tkent@chromium.org1c1b7542012-06-21 01:31:08 +000076}
77
78// ----------------------------------------------------------------------------
79
tkent@chromium.org00fa35f2012-07-18 04:16:13 +000080class FormElementKey {
81public:
tkent@chromium.org79ff7c22012-07-19 02:48:51 +000082 FormElementKey(AtomicStringImpl* = 0, AtomicStringImpl* = 0);
tkent@chromium.org00fa35f2012-07-18 04:16:13 +000083 ~FormElementKey();
84 FormElementKey(const FormElementKey&);
85 FormElementKey& operator=(const FormElementKey&);
86
87 AtomicStringImpl* name() const { return m_name; }
88 AtomicStringImpl* type() const { return m_type; }
tkent@chromium.org00fa35f2012-07-18 04:16:13 +000089
90 // Hash table deleted values, which are only constructed and never copied or destroyed.
91 FormElementKey(WTF::HashTableDeletedValueType) : m_name(hashTableDeletedValue()) { }
92 bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValue(); }
93
94private:
95 void ref() const;
96 void deref() const;
97
98 static AtomicStringImpl* hashTableDeletedValue() { return reinterpret_cast<AtomicStringImpl*>(-1); }
99
100 AtomicStringImpl* m_name;
101 AtomicStringImpl* m_type;
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000102};
103
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000104FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000105 : m_name(name)
106 , m_type(type)
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000107{
108 ref();
109}
110
111FormElementKey::~FormElementKey()
112{
113 deref();
114}
115
116FormElementKey::FormElementKey(const FormElementKey& other)
117 : m_name(other.name())
118 , m_type(other.type())
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000119{
120 ref();
121}
122
123FormElementKey& FormElementKey::operator=(const FormElementKey& other)
124{
125 other.ref();
126 deref();
127 m_name = other.name();
128 m_type = other.type();
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000129 return *this;
130}
131
132void FormElementKey::ref() const
133{
134 if (name())
135 name()->ref();
136 if (type())
137 type()->ref();
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000138}
139
140void FormElementKey::deref() const
141{
142 if (name())
143 name()->deref();
144 if (type())
145 type()->deref();
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000146}
147
148inline bool operator==(const FormElementKey& a, const FormElementKey& b)
149{
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000150 return a.name() == b.name() && a.type() == b.type();
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000151}
152
153struct FormElementKeyHash {
154 static unsigned hash(const FormElementKey&);
155 static bool equal(const FormElementKey& a, const FormElementKey& b) { return a == b; }
156 static const bool safeToCompareToEmptyOrDeleted = true;
157};
158
159unsigned FormElementKeyHash::hash(const FormElementKey& key)
160{
161 return StringHasher::hashMemory<sizeof(FormElementKey)>(&key);
162}
163
164struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> {
165 static void constructDeletedValue(FormElementKey& slot) { new (NotNull, &slot) FormElementKey(WTF::HashTableDeletedValue); }
166 static bool isDeletedValue(const FormElementKey& value) { return value.isHashTableDeletedValue(); }
167};
168
169// ----------------------------------------------------------------------------
170
171class SavedFormState {
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000172 WTF_MAKE_NONCOPYABLE(SavedFormState);
173 WTF_MAKE_FAST_ALLOCATED;
174
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000175public:
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000176 SavedFormState()
177 : m_controlStateCount(0)
178 {
179 }
180
181 static std::unique_ptr<SavedFormState> deserialize(const Vector<String>&, size_t& index);
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000182 void serializeTo(Vector<String>&) const;
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000183 bool isEmpty() const { return m_stateForNewFormElements.isEmpty(); }
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000184 void appendControlState(const AtomicString& name, const AtomicString& type, const FormControlState&);
185 FormControlState takeControlState(const AtomicString& name, const AtomicString& type);
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000186
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000187 Vector<String> getReferencedFilePaths() const;
188
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000189private:
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000190 typedef HashMap<FormElementKey, Deque<FormControlState>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
191 FormElementStateMap m_stateForNewFormElements;
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000192 size_t m_controlStateCount;
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000193};
194
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000195static bool isNotFormControlTypeCharacter(UChar ch)
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000196{
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000197 return ch != '-' && (ch > 'z' || ch < 'a');
198}
199
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000200std::unique_ptr<SavedFormState> SavedFormState::deserialize(const Vector<String>& stateVector, size_t& index)
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000201{
202 if (index >= stateVector.size())
203 return nullptr;
204 // FIXME: We need String::toSizeT().
205 size_t itemCount = stateVector[index++].toUInt();
206 if (!itemCount)
207 return nullptr;
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000208 auto savedFormState = std::make_unique<SavedFormState>();
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000209 while (itemCount--) {
210 if (index + 1 >= stateVector.size())
211 return nullptr;
212 String name = stateVector[index++];
213 String type = stateVector[index++];
214 FormControlState state = FormControlState::deserialize(stateVector, index);
215 if (type.isEmpty() || type.find(isNotFormControlTypeCharacter) != notFound || state.isFailure())
216 return nullptr;
217 savedFormState->appendControlState(name, type, state);
218 }
zandobersek@gmail.com7f7a7d72014-03-31 14:36:16 +0000219 return savedFormState;
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000220}
221
222void SavedFormState::serializeTo(Vector<String>& stateVector) const
223{
224 stateVector.append(String::number(m_controlStateCount));
225 for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begin(); it != m_stateForNewFormElements.end(); ++it) {
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000226 const FormElementKey& key = it->key;
227 const Deque<FormControlState>& queue = it->value;
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000228 for (Deque<FormControlState>::const_iterator queIterator = queue.begin(); queIterator != queue.end(); ++queIterator) {
229 stateVector.append(key.name());
230 stateVector.append(key.type());
231 queIterator->serializeTo(stateVector);
232 }
233 }
234}
235
236void SavedFormState::appendControlState(const AtomicString& name, const AtomicString& type, const FormControlState& state)
237{
238 FormElementKey key(name.impl(), type.impl());
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000239 FormElementStateMap::iterator it = m_stateForNewFormElements.find(key);
240 if (it != m_stateForNewFormElements.end())
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000241 it->value.append(state);
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000242 else {
243 Deque<FormControlState> stateList;
244 stateList.append(state);
245 m_stateForNewFormElements.set(key, stateList);
246 }
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000247 m_controlStateCount++;
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000248}
249
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000250FormControlState SavedFormState::takeControlState(const AtomicString& name, const AtomicString& type)
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000251{
252 if (m_stateForNewFormElements.isEmpty())
253 return FormControlState();
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000254 FormElementStateMap::iterator it = m_stateForNewFormElements.find(FormElementKey(name.impl(), type.impl()));
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000255 if (it == m_stateForNewFormElements.end())
256 return FormControlState();
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000257 ASSERT(it->value.size());
258 FormControlState state = it->value.takeFirst();
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000259 m_controlStateCount--;
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000260 if (!it->value.size())
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000261 m_stateForNewFormElements.remove(it);
262 return state;
263}
264
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000265Vector<String> SavedFormState::getReferencedFilePaths() const
266{
267 Vector<String> toReturn;
268 for (FormElementStateMap::const_iterator it = m_stateForNewFormElements.begin(); it != m_stateForNewFormElements.end(); ++it) {
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000269 const FormElementKey& key = it->key;
benjamin@webkit.orgdbf95292012-11-09 01:15:59 +0000270 if (!equal(key.type(), "file", 4))
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000271 continue;
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000272 const Deque<FormControlState>& queue = it->value;
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000273 for (Deque<FormControlState>::const_iterator queIterator = queue.begin(); queIterator != queue.end(); ++queIterator) {
274 const Vector<FileChooserFileInfo>& selectedFiles = HTMLInputElement::filesFromFileInputFormControlState(*queIterator);
275 for (size_t i = 0; i < selectedFiles.size(); ++i)
276 toReturn.append(selectedFiles[i].path);
277 }
278 }
279 return toReturn;
280}
281
tkent@chromium.org00fa35f2012-07-18 04:16:13 +0000282// ----------------------------------------------------------------------------
283
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000284class FormKeyGenerator {
285 WTF_MAKE_NONCOPYABLE(FormKeyGenerator);
286 WTF_MAKE_FAST_ALLOCATED;
287
288public:
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000289 FormKeyGenerator() = default;
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000290 AtomicString formKey(const HTMLFormControlElementWithState&);
291 void willDeleteForm(HTMLFormElement*);
292
293private:
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000294 typedef HashMap<HTMLFormElement*, AtomicString> FormToKeyMap;
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000295 typedef HashMap<String, unsigned> FormSignatureToNextIndexMap;
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000296 FormToKeyMap m_formToKeyMap;
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000297 FormSignatureToNextIndexMap m_formSignatureToNextIndexMap;
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000298};
299
tkent@chromium.org6d810422012-07-20 04:48:17 +0000300static inline void recordFormStructure(const HTMLFormElement& form, StringBuilder& builder)
301{
302 // 2 is enough to distinguish forms in webkit.org/b/91209#c0
303 const size_t namedControlsToBeRecorded = 2;
304 const Vector<FormAssociatedElement*>& controls = form.associatedElements();
commit-queue@webkit.orgba752502014-09-03 18:42:54 +0000305 builder.appendLiteral(" [");
tkent@chromium.org6d810422012-07-20 04:48:17 +0000306 for (size_t i = 0, namedControls = 0; i < controls.size() && namedControls < namedControlsToBeRecorded; ++i) {
307 if (!controls[i]->isFormControlElementWithState())
308 continue;
309 HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(controls[i]);
310 if (!ownerFormForState(*control))
311 continue;
312 AtomicString name = control->name();
313 if (name.isEmpty())
314 continue;
315 namedControls++;
316 builder.append(name);
commit-queue@webkit.orgba752502014-09-03 18:42:54 +0000317 builder.append(' ');
tkent@chromium.org6d810422012-07-20 04:48:17 +0000318 }
commit-queue@webkit.orgba752502014-09-03 18:42:54 +0000319 builder.append(']');
tkent@chromium.org6d810422012-07-20 04:48:17 +0000320}
321
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000322static inline String formSignature(const HTMLFormElement& form)
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000323{
darin@apple.com5ffbb5c2013-09-27 16:39:41 +0000324 URL actionURL = form.getURLAttribute(actionAttr);
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000325 // Remove the query part because it might contain volatile parameters such
326 // as a session key.
327 actionURL.setQuery(String());
328 StringBuilder builder;
329 if (!actionURL.isEmpty())
330 builder.append(actionURL.string());
tkent@chromium.org6d810422012-07-20 04:48:17 +0000331
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000332 recordFormStructure(form, builder);
333 return builder.toString();
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000334}
335
336AtomicString FormKeyGenerator::formKey(const HTMLFormControlElementWithState& control)
337{
tkent@chromium.org03055db2012-07-13 10:59:59 +0000338 HTMLFormElement* form = ownerFormForState(control);
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000339 if (!form) {
svillar@igalia.com5b31eef2014-03-14 08:30:55 +0000340 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, formKeyForNoOwner, ("No owner", AtomicString::ConstructFromLiteral));
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000341 return formKeyForNoOwner;
342 }
343 FormToKeyMap::const_iterator it = m_formToKeyMap.find(form);
344 if (it != m_formToKeyMap.end())
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000345 return it->value;
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000346
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000347 String signature = formSignature(*form);
348 ASSERT(!signature.isNull());
349 FormSignatureToNextIndexMap::AddResult result = m_formSignatureToNextIndexMap.add(signature, 0);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000350 unsigned nextIndex = result.iterator->value++;
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000351
352 StringBuilder builder;
353 builder.append(signature);
paroga@webkit.org4d255972012-09-10 04:19:34 +0000354 builder.appendLiteral(" #");
355 builder.appendNumber(nextIndex);
tkent@chromium.org0f449f92012-07-26 01:36:33 +0000356 AtomicString formKey = builder.toAtomicString();
357 m_formToKeyMap.add(form, formKey);
358 return formKey;
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000359}
360
361void FormKeyGenerator::willDeleteForm(HTMLFormElement* form)
362{
363 ASSERT(form);
rniwa@webkit.orgc8e018e2013-06-18 21:25:53 +0000364 m_formToKeyMap.remove(form);
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000365}
366
367// ----------------------------------------------------------------------------
tkent@chromium.org1c1b7542012-06-21 01:31:08 +0000368
tkent@chromium.org34554872012-06-08 09:53:52 +0000369FormController::FormController()
370{
371}
372
373FormController::~FormController()
374{
375}
376
dbates@webkit.org1edd81d2013-12-18 00:15:02 +0000377unsigned FormController::formElementsCharacterCount() const
378{
379 unsigned count = 0;
380 for (auto& element : m_formElementsWithState) {
381 FormControlState state = element->saveFormControlState();
382 if (state.valueSize() && element->isTextFormControl())
383 count += state[0].length();
384 }
385 return count;
386}
387
tkent@chromium.org1c1b7542012-06-21 01:31:08 +0000388static String formStateSignature()
389{
390 // In the legacy version of serialized state, the first item was a name
391 // attribute value of a form control. The following string literal should
392 // contain some characters which are rarely used for name attribute values.
svillar@igalia.com5b31eef2014-03-14 08:30:55 +0000393 DEPRECATED_DEFINE_STATIC_LOCAL(String, signature, (ASCIILiteral("\n\r?% WebKit serialized form state version 8 \n\r=&")));
tkent@chromium.org1c1b7542012-06-21 01:31:08 +0000394 return signature;
395}
396
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000397std::unique_ptr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormElementListHashSet& controlList)
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000398{
zandobersek@gmail.com7f7a7d72014-03-31 14:36:16 +0000399 FormKeyGenerator keyGenerator;
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000400 auto stateMap = std::make_unique<SavedFormStateMap>();
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000401 for (FormElementListHashSet::const_iterator it = controlList.begin(); it != controlList.end(); ++it) {
rniwa@webkit.org211e4782013-05-30 04:17:28 +0000402 HTMLFormControlElementWithState* control = it->get();
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000403 if (!control->shouldSaveAndRestoreFormControlState())
404 continue;
zandobersek@gmail.com7f7a7d72014-03-31 14:36:16 +0000405 auto& formState = stateMap->add(keyGenerator.formKey(*control).impl(), nullptr).iterator->value;
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000406 if (!formState)
407 formState = std::make_unique<SavedFormState>();
408 formState->appendControlState(control->name(), control->type(), control->saveFormControlState());
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000409 }
zandobersek@gmail.coma1993ca2014-04-13 14:18:48 +0000410 return stateMap;
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000411}
412
tkent@chromium.org34554872012-06-08 09:53:52 +0000413Vector<String> FormController::formElementsState() const
414{
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000415 std::unique_ptr<SavedFormStateMap> stateMap = createSavedFormStateMap(m_formElementsWithState);
tkent@chromium.org34554872012-06-08 09:53:52 +0000416 Vector<String> stateVector;
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000417 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4);
tkent@chromium.org1c1b7542012-06-21 01:31:08 +0000418 stateVector.append(formStateSignature());
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000419 for (SavedFormStateMap::const_iterator it = stateMap->begin(); it != stateMap->end(); ++it) {
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000420 stateVector.append(it->key.get());
421 it->value->serializeTo(stateVector);
tkent@chromium.org34554872012-06-08 09:53:52 +0000422 }
tkent@chromium.orgd8143ab2012-07-12 07:31:14 +0000423 bool hasOnlySignature = stateVector.size() == 1;
424 if (hasOnlySignature)
425 stateVector.clear();
tkent@chromium.org34554872012-06-08 09:53:52 +0000426 return stateVector;
427}
428
429void FormController::setStateForNewFormElements(const Vector<String>& stateVector)
430{
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000431 formStatesFromStateVector(stateVector, m_savedFormStateMap);
tkent@chromium.org34554872012-06-08 09:53:52 +0000432}
433
tkent@chromium.org92bad1a2012-06-26 07:55:18 +0000434FormControlState FormController::takeStateForFormElement(const HTMLFormControlElementWithState& control)
tkent@chromium.org34554872012-06-08 09:53:52 +0000435{
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000436 if (m_savedFormStateMap.isEmpty())
tkent@chromium.org92bad1a2012-06-26 07:55:18 +0000437 return FormControlState();
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000438 if (!m_formKeyGenerator)
zandobersek@gmail.come99d2662014-03-31 10:35:59 +0000439 m_formKeyGenerator = std::make_unique<FormKeyGenerator>();
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000440 SavedFormStateMap::iterator it = m_savedFormStateMap.find(m_formKeyGenerator->formKey(control).impl());
441 if (it == m_savedFormStateMap.end())
442 return FormControlState();
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000443 FormControlState state = it->value->takeControlState(control.name(), control.type());
444 if (it->value->isEmpty())
tkent@chromium.org79ff7c22012-07-19 02:48:51 +0000445 m_savedFormStateMap.remove(it);
tkent@chromium.orgd08b5512012-06-19 06:20:48 +0000446 return state;
tkent@chromium.org34554872012-06-08 09:53:52 +0000447}
448
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000449void FormController::formStatesFromStateVector(const Vector<String>& stateVector, SavedFormStateMap& map)
450{
451 map.clear();
452
453 size_t i = 0;
454 if (stateVector.size() < 1 || stateVector[i++] != formStateSignature())
455 return;
456
457 while (i + 1 < stateVector.size()) {
458 AtomicString formKey = stateVector[i++];
zandobersek@gmail.com7f7a7d72014-03-31 14:36:16 +0000459 auto state = SavedFormState::deserialize(stateVector, i);
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000460 if (!state) {
461 i = 0;
462 break;
463 }
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +0000464 map.add(formKey.impl(), WTF::move(state));
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000465 }
466 if (i != stateVector.size())
467 map.clear();
468}
469
tkent@chromium.orgb53db042012-06-28 08:48:20 +0000470void FormController::willDeleteForm(HTMLFormElement* form)
471{
472 if (m_formKeyGenerator)
473 m_formKeyGenerator->willDeleteForm(form);
474}
475
tkent@chromium.org03055db2012-07-13 10:59:59 +0000476void FormController::restoreControlStateFor(HTMLFormControlElementWithState& control)
477{
478 // We don't save state of a control with shouldSaveAndRestoreFormControlState()
479 // == false. But we need to skip restoring process too because a control in
480 // another form might have the same pair of name and type and saved its state.
481 if (!control.shouldSaveAndRestoreFormControlState())
482 return;
483 if (ownerFormForState(control))
484 return;
485 FormControlState state = takeStateForFormElement(control);
486 if (state.valueSize() > 0)
487 control.restoreFormControlState(state);
488}
489
490void FormController::restoreControlStateIn(HTMLFormElement& form)
491{
492 const Vector<FormAssociatedElement*>& elements = form.associatedElements();
493 for (size_t i = 0; i < elements.size(); ++i) {
494 if (!elements[i]->isFormControlElementWithState())
495 continue;
496 HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(elements[i]);
497 if (!control->shouldSaveAndRestoreFormControlState())
498 continue;
499 if (ownerFormForState(*control) != &form)
500 continue;
501 FormControlState state = takeStateForFormElement(*control);
502 if (state.valueSize() > 0)
503 control->restoreFormControlState(state);
504 }
505}
506
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000507Vector<String> FormController::getReferencedFilePaths(const Vector<String>& stateVector)
508{
509 Vector<String> toReturn;
510 SavedFormStateMap map;
511 formStatesFromStateVector(stateVector, map);
andersca@apple.com92012992013-05-05 19:03:49 +0000512 for (SavedFormStateMap::const_iterator it = map.begin(), end = map.end(); it != end; ++it)
513 toReturn.appendVector(it->value->getReferencedFilePaths());
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000514 return toReturn;
515}
tkent@chromium.org34554872012-06-08 09:53:52 +0000516
rniwa@webkit.org211e4782013-05-30 04:17:28 +0000517void FormController::registerFormElementWithState(HTMLFormControlElementWithState* control)
518{
519 ASSERT(!m_formElementsWithState.contains(control));
520 m_formElementsWithState.add(control);
521}
522
523void FormController::unregisterFormElementWithState(HTMLFormControlElementWithState* control)
524{
525 ASSERT(m_formElementsWithState.contains(control));
526 m_formElementsWithState.remove(control);
527}
528
commit-queue@webkit.org2f936c82012-08-16 08:52:25 +0000529} // namespace WebCore