Form state restore: Need to identify a form by its content
https://bugs.webkit.org/show_bug.cgi?id=91209

Reviewed by Hajime Morita.

Source/WebCore:

Add names of the first two controls of a form to its formKey
string. By this change, we can correctly restore states to
reordered forms like webkit.org/b/91209#c0.

Tests: Added test cases to fast/forms/state-restore-per-form.html.

* html/FormController.cpp:
(WebCore::recordFormStructure):
Append at most two name attribute values.
(WebCore::createKey): Insert a string built by recordFromStructure().
(WebCore::formStateSignature): Bump the version.

LayoutTests:

* fast/forms/state-restore-broken-state-expected.txt:
Updated for the serialized format change.
* fast/forms/state-restore-per-form-expected.txt:
* fast/forms/state-restore-per-form.html:
- Add a control to #form2 before 'additionalControl'
 We can't identify this form if the second named control is changed.
- Add test cases of webkit.org/b/91209#c0.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@123178 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/html/FormController.cpp b/Source/WebCore/html/FormController.cpp
index 7a992b8..35594b8 100644
--- a/Source/WebCore/html/FormController.cpp
+++ b/Source/WebCore/html/FormController.cpp
@@ -282,6 +282,28 @@
     HashSet<AtomicString> m_existingKeys;
 };
 
+static inline void recordFormStructure(const HTMLFormElement& form, StringBuilder& builder)
+{
+    // 2 is enough to distinguish forms in webkit.org/b/91209#c0
+    const size_t namedControlsToBeRecorded = 2;
+    const Vector<FormAssociatedElement*>& controls = form.associatedElements();
+    builder.append(" [");
+    for (size_t i = 0, namedControls = 0; i < controls.size() && namedControls < namedControlsToBeRecorded; ++i) {
+        if (!controls[i]->isFormControlElementWithState())
+            continue;
+        HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(controls[i]);
+        if (!ownerFormForState(*control))
+            continue;
+        AtomicString name = control->name();
+        if (name.isEmpty())
+            continue;
+        namedControls++;
+        builder.append(name);
+        builder.append(" ");
+    }
+    builder.append("]");
+}
+
 static inline AtomicString createKey(HTMLFormElement* form, unsigned index)
 {
     ASSERT(form);
@@ -292,6 +314,9 @@
     StringBuilder builder;
     if (!actionURL.isEmpty())
         builder.append(actionURL.string());
+
+    recordFormStructure(*form, builder);
+
     builder.append(" #");
     builder.append(String::number(index));
     return builder.toAtomicString();
@@ -344,7 +369,7 @@
     // In the legacy version of serialized state, the first item was a name
     // attribute value of a form control. The following string literal should
     // contain some characters which are rarely used for name attribute values.
-    DEFINE_STATIC_LOCAL(String, signature, ("\n\r?% WebKit serialized form state version 6 \n\r=&"));
+    DEFINE_STATIC_LOCAL(String, signature, ("\n\r?% WebKit serialized form state version 7 \n\r=&"));
     return signature;
 }