Changeset 120895 in webkit
- Timestamp:
- Jun 20, 2012 6:31:08 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r120894 r120895 1 2012-06-20 Kent Tamura <tkent@chromium.org> 2 3 Unmodified form control value are overwritten by another form 4 control value with the same name after navigating and going back 5 https://bugs.webkit.org/show_bug.cgi?id=89409 6 7 Reviewed by Hajime Morita. 8 9 * fast/forms/resources/state-restore-broken-state-2.html: 10 Take care of the signature string at the beginning of the array. 11 * fast/forms/state-restore-broken-state-expected.txt: 12 Updated for the serialized format change. 13 * fast/forms/state-restore-to-non-edited-controls-expected.txt: 14 * fast/forms/state-restore-to-non-edited-controls.html: 15 Add a test for a case of duplicated names. 16 1 17 2012-06-20 Adam Barth <abarth@webkit.org> 2 18 -
trunk/LayoutTests/fast/forms/resources/state-restore-broken-state-2.html
r120397 r120895 1 1 <script> 2 2 setTimeout(function() { 3 console.log('Generated state: [' + internals.formControlStateOfPreviousHistoryItem() + ']'); 3 var stateArray = internals.formControlStateOfPreviousHistoryItem(); 4 // Omit the signature string because it is volatile. 5 console.log('Generated state: [' + stateArray.slice(1) + ']'); 4 6 5 internals.setFormControlStateOfPreviousHistoryItem(['name1', 'text', 'modified', '***broken***']); 7 stateArray.push('***broken***'); 8 internals.setFormControlStateOfPreviousHistoryItem(stateArray); 6 9 parent.didLoadAnotherDocument(); 7 10 }, 0); -
trunk/LayoutTests/fast/forms/state-restore-broken-state-expected.txt
r120397 r120895 1 CONSOLE MESSAGE: line 3: Generated state: [name1,text,modified]1 CONSOLE MESSAGE: line 5: Generated state: [name1,text,1,modified] 2 2 The value was modified in the first load of state-restore-broken-state-1.html, but it should not be restored because the state-restore-broken-state-2.html breaks the state. 3 3 -
trunk/LayoutTests/fast/forms/state-restore-to-non-edited-controls-expected.txt
r120796 r120895 6 6 PASS document.getElementById("reset").value is "2" 7 7 PASS document.getElementById("submit1").value is "2" 8 PASS document.getElementById("text0").value is "2" 8 9 PASS document.getElementById("text1").value is "edit" 9 10 PASS document.getElementById("text2").value is "2" -
trunk/LayoutTests/fast/forms/state-restore-to-non-edited-controls.html
r120796 r120895 14 14 <script> 15 15 16 function makeForm(parent, buttonValue, hiddenValue, imageValue, resetValue, submitValue, textValue 1, textValue2, textAreaValue) {16 function makeForm(parent, buttonValue, hiddenValue, imageValue, resetValue, submitValue, textValue0, textValue1, textValue2, textAreaValue) { 17 17 document.write('<form action="data:text/html,<script>history.back()</script>" id=form1>' 18 18 + '<input name=button id=button type=button value="' + buttonValue + '">' … … 21 21 + '<input name=reset id=reset type=reset value="' + resetValue + '">' 22 22 + '<input name=submit1 id=submit1 type=submit value="' + submitValue + '">' 23 + '<input name=text1 id=text0 type=text value="' + textValue0 + '">' 23 24 + '<input name=text1 id=text1 type=text value="' + textValue1 + '">' 24 25 + '<input name=text2 id=text2 type=text value="' + textValue2 + '">' … … 36 37 layoutTestController.waitUntilDone(); 37 38 state.value = 'visited'; 38 makeForm(parent, '1', '1', '1', '1', '1', '1', '1', '1' );39 makeForm(parent, '1', '1', '1', '1', '1', '1', '1', '1', '1'); 39 40 40 41 document.getElementById('text1').value = 'edit'; … … 43 44 } else { 44 45 // Second visit. 45 makeForm(parent, '2', '2', '2', '2', '2', '2', '2', '2' );46 makeForm(parent, '2', '2', '2', '2', '2', '2', '2', '2', '2'); 46 47 47 48 shouldBe('document.getElementById("button").value', '"2"'); … … 50 51 shouldBe('document.getElementById("reset").value', '"2"'); 51 52 shouldBe('document.getElementById("submit1").value', '"2"'); 53 shouldBe('document.getElementById("text0").value', '"2"'); 52 54 shouldBe('document.getElementById("text1").value', '"edit"'); 53 55 shouldBe('document.getElementById("text2").value', '"2"'); -
trunk/Source/WebCore/ChangeLog
r120893 r120895 1 2012-06-20 Kent Tamura <tkent@chromium.org> 2 3 Unmodified form control value are overwritten by another form 4 control value with the same name after navigating and going back 5 https://bugs.webkit.org/show_bug.cgi?id=89409 6 7 Reviewed by Hajime Morita. 8 9 Detail of the bug: 10 If a page had multiple form controls of which names and types were 11 identical like the following: 12 <input type=text name=name1 id=input1> 13 <input type=text name=name1 id=input2> 14 and a user updated the value of the second control, then went to 15 another page and went back to the page again, we restored the updated 16 value to the first element, and didn't update the second element. 17 18 We didn't save unmodified control state, and the form state data 19 had no ways to represent "this control should be skipped". 20 21 How to resovle the bug: 22 We need to represent "this control should be skipped" in the 23 seriazlied form state vector. 24 25 - A serialized control state had three items: 26 name, type, value. 27 Now we change it to: 28 name, type, flag, optional value 29 30 - It is definitely incompatible with serizlized state produced by 31 older WebCore. So, we need to add the signature string to 32 represent the version of serialized state format. 33 34 - Because the state for a form control is variable-length and we 35 can't deserialize it in reverse-order, we change the on-memory 36 representation from Vector<> to Deque<>. 37 38 Test: fast/forms/state-restore-to-non-edited-controls.html 39 40 * html/FormController.cpp: 41 (WebCore::FormControlState::serializeTo): 42 Added. Serialize a state for a form control to a string vector. 43 (WebCore::FormControlState::deserialize): 44 Added. Produce a FormControlState object from the specified string vector. 45 It can produce a FromControlState of the failure type. 46 (WebCore::formStateSignature): The signature string of the serialized state. 47 (WebCore::FormController::formElementsState): 48 - Capacity: 49 The size of seirlized data for one form control is typically 4. 50 +1 for the signature. 51 - We need to store a FormControlState with no values. 52 (WebCore::FormController::setStateForNewFormElements): 53 - We can't iterate over the stateVector in reverse order any more 54 because serialized control state is variable-length. 55 - We put FormControlState objects to HashMap instead of String objects. 56 (WebCore::FormController::takeStateForFormElement): 57 Updated for Deque<>. 58 * html/FormController.h: 59 (FormControlState): Declare deserialize() and serializeTo(). 60 (WebCore::FormControlState::isFailure): Added. 61 (WebCore::FormControlState::FormControlState): 62 Added to create a FormControlState with failure type. 63 (FormController): 64 Change the value type of m_stateForNewFormElements from Vector<String> 65 to Deque<FormControlState>. 66 1 67 2012-06-20 Alexandru Chiculita <achicu@adobe.com> 2 68 -
trunk/Source/WebCore/html/FormController.cpp
r120679 r120895 28 28 using namespace HTMLNames; 29 29 30 // ---------------------------------------------------------------------------- 31 32 // Serilized form of FormControlState: 33 // (',' means strings around it are separated in stateVector.) 34 // 35 // SerializedControlState ::= SkipState | SingleValueState 36 // SkipState ::= '0' 37 // SingleValueState ::= '1', ControlValue 38 // ControlValue ::= arbitrary string 39 40 void FormControlState::serializeTo(Vector<String>& stateVector) const 41 { 42 ASSERT(!isFailure()); 43 if (!hasValue()) 44 stateVector.append("0"); 45 else { 46 stateVector.append("1"); 47 stateVector.append(m_value); 48 } 49 } 50 51 FormControlState FormControlState::deserialize(const Vector<String>& stateVector, size_t& index) 52 { 53 if (index >= stateVector.size()) 54 return FormControlState(TypeFailure); 55 uint64_t valueSize = stateVector[index++].toUInt64(); 56 if (!valueSize) 57 return FormControlState(); 58 if (valueSize != 1 || index + 1 > stateVector.size()) 59 return FormControlState(TypeFailure); 60 return FormControlState(stateVector[index++]); 61 } 62 63 // ---------------------------------------------------------------------------- 64 65 30 66 FormController::FormController() 31 67 { … … 36 72 } 37 73 74 static String formStateSignature() 75 { 76 // In the legacy version of serialized state, the first item was a name 77 // attribute value of a form control. The following string literal should 78 // contain some characters which are rarely used for name attribute values. 79 DEFINE_STATIC_LOCAL(String, signature, ("\n\r?% WebKit serialized form state version 1 \n\r=&")); 80 return signature; 81 } 82 38 83 Vector<String> FormController::formElementsState() const 39 84 { 40 85 Vector<String> stateVector; 41 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 3); 86 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 4 + 1); 87 stateVector.append(formStateSignature()); 42 88 typedef FormElementListHashSet::const_iterator Iterator; 43 89 Iterator end = m_formElementsWithState.end(); … … 46 92 if (!elementWithState->shouldSaveAndRestoreFormControlState()) 47 93 continue; 48 FormControlState state = elementWithState->saveFormControlState();49 if (!state.hasValue())50 continue;51 94 stateVector.append(elementWithState->name().string()); 52 95 stateVector.append(elementWithState->formControlType().string()); 53 stateVector.append(state.value());96 elementWithState->saveFormControlState().serializeTo(stateVector); 54 97 } 55 98 return stateVector; … … 63 106 void FormController::setStateForNewFormElements(const Vector<String>& stateVector) 64 107 { 65 // Walk the state vector backwards so that the value to use for each66 // name/type pair first is the one at the end of each individual vector67 // in the FormElementStateMap. We're using them like stacks.68 108 typedef FormElementStateMap::iterator Iterator; 69 109 m_formElementsWithState.clear(); 70 110 71 if (stateVector.size() % 3) 111 size_t i = 0; 112 if (stateVector.size() < 1 || stateVector[i++] != formStateSignature()) 72 113 return; 73 for (size_t i = 0; i < stateVector.size(); i += 3) { 74 if (stateVector[i + 1].find(isNotFormControlTypeCharacter) != notFound) 75 return; 76 } 77 78 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) { 79 AtomicString name = stateVector[i - 3]; 80 AtomicString type = stateVector[i - 2]; 81 const String& value = stateVector[i - 1]; 114 115 while (i + 2 < stateVector.size()) { 116 AtomicString name = stateVector[i++]; 117 AtomicString type = stateVector[i++]; 118 FormControlState state = FormControlState::deserialize(stateVector, i); 119 if (type.isEmpty() || type.impl()->find(isNotFormControlTypeCharacter) != notFound || state.isFailure()) 120 break; 121 82 122 FormElementKey key(name.impl(), type.impl()); 83 123 Iterator it = m_stateForNewFormElements.find(key); 84 124 if (it != m_stateForNewFormElements.end()) 85 it->second.append( value);125 it->second.append(state); 86 126 else { 87 Vector<String> valueList(1);88 valueList[0] = value;89 m_stateForNewFormElements.set(key, valueList);127 Deque<FormControlState> stateList; 128 stateList.append(state); 129 m_stateForNewFormElements.set(key, stateList); 90 130 } 91 131 } 132 if (i != stateVector.size()) 133 m_stateForNewFormElements.clear(); 92 134 } 93 135 … … 104 146 return FormControlState(); 105 147 ASSERT(it->second.size()); 106 FormControlState state(it->second.last()); 107 if (it->second.size() > 1) 108 it->second.removeLast(); 109 else 148 FormControlState state = it->second.takeFirst(); 149 if (!it->second.size()) 110 150 m_stateForNewFormElements.remove(it); 111 151 return state; -
trunk/Source/WebCore/html/FormController.h
r120679 r120895 24 24 25 25 #include "CheckedRadioButtons.h" 26 #include <wtf/Deque.h> 26 27 #include <wtf/Forward.h> 27 28 #include <wtf/ListHashSet.h> … … 78 79 FormControlState() : m_type(TypeSkip) { } 79 80 explicit FormControlState(const String& value) : m_type(TypeRestore), m_value(value) { } 81 static FormControlState deserialize(const Vector<String>& stateVector, size_t& index); 80 82 FormControlState(const FormControlState& another) : m_type(another.m_type), m_value(another.m_value) { } 81 83 FormControlState& operator=(const FormControlState&); 82 84 85 bool isFailure() const { return m_type == TypeFailure; } 83 86 bool hasValue() const { return m_type == TypeRestore; } 84 87 String value() const { return m_value; } 88 void serializeTo(Vector<String>& stateVector) const; 85 89 86 90 private: 87 enum Type { TypeSkip, TypeRestore }; 91 enum Type { TypeSkip, TypeRestore, TypeFailure }; 92 explicit FormControlState(Type type) : m_type(type) { } 93 88 94 Type m_type; 89 95 String m_value; … … 130 136 FormAssociatedElementListHashSet m_formElementsWithFormAttribute; 131 137 132 typedef HashMap<FormElementKey, Vector<String>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;138 typedef HashMap<FormElementKey, Deque<FormControlState>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap; 133 139 FormElementStateMap m_stateForNewFormElements; 134 140
Note: See TracChangeset
for help on using the changeset viewer.