TEST_F(HTMLSelectElementTest, SaveRestoreSelectSingleFormControlState) { document().documentElement()->setInnerHTML( String("<!DOCTYPE HTML><select id='sel'>" "<option value='111' id='0'>111</option>" "<option value='222'>222</option>" "<option value='111' selected id='2'>!666</option>" "<option value='999'>999</option></select>"), ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); Element* element = document().getElementById("sel"); HTMLFormControlElementWithState* select = toHTMLSelectElement(element); HTMLOptionElement* opt0 = toHTMLOptionElement(document().getElementById("0")); HTMLOptionElement* opt2 = toHTMLOptionElement(document().getElementById("2")); // Save the select element state, and then restore again. // Test passes if the restored state is not changed. EXPECT_EQ(2, toHTMLSelectElement(element)->selectedIndex()); EXPECT_FALSE(opt0->selected()); EXPECT_TRUE(opt2->selected()); FormControlState selectState = select->saveFormControlState(); EXPECT_EQ(2U, selectState.valueSize()); // Clear the selected state, to be restored by restoreFormControlState. toHTMLSelectElement(select)->setSelectedIndex(-1); ASSERT_FALSE(opt2->selected()); // Restore select->restoreFormControlState(selectState); EXPECT_EQ(2, toHTMLSelectElement(element)->selectedIndex()); EXPECT_FALSE(opt0->selected()); EXPECT_TRUE(opt2->selected()); }
TEST_F(HTMLSelectElementTest, RestoreUnmatchedFormControlState) { // We had a bug that selectedOption() and m_lastOnChangeOption were // mismatched in optionToBeShown(). It happened when // restoreFormControlState() couldn't find matched OPTIONs. // crbug.com/627833. document().documentElement()->setInnerHTML( "<select id='sel'>" "<option selected>Default</option>" "<option id='2'>222</option>" "</select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); Element* element = document().getElementById("sel"); HTMLFormControlElementWithState* select = toHTMLSelectElement(element); HTMLOptionElement* opt2 = toHTMLOptionElement(document().getElementById("2")); toHTMLSelectElement(element)->setSelectedIndex(1); // Save the current state. FormControlState selectState = select->saveFormControlState(); EXPECT_EQ(2U, selectState.valueSize()); // Reset the status. select->reset(); ASSERT_FALSE(opt2->selected()); element->removeChild(opt2); // Restore select->restoreFormControlState(selectState); EXPECT_EQ(-1, toHTMLSelectElement(element)->selectedIndex()); EXPECT_EQ(nullptr, toHTMLSelectElement(element)->optionToBeShown()); }
void FormController::restoreControlStateFor(HTMLFormControlElementWithState& control) { // We don't save state of a control with shouldSaveAndRestoreFormControlState() // == false. But we need to skip restoring process too because a control in // another form might have the same pair of name and type and saved its state. if (!control.shouldSaveAndRestoreFormControlState()) return; if (ownerFormForState(control)) return; FormControlState state = takeStateForFormElement(control); if (state.valueSize() > 0) control.restoreFormControlState(state); }
FormControlState FormController::takeStateForFormElement(const HTMLFormControlElementWithState& control) { if (m_savedFormStateMap.isEmpty()) return FormControlState(); if (!m_formKeyGenerator) m_formKeyGenerator = std::make_unique<FormKeyGenerator>(); SavedFormStateMap::iterator it = m_savedFormStateMap.find(m_formKeyGenerator->formKey(control).impl()); if (it == m_savedFormStateMap.end()) return FormControlState(); FormControlState state = it->value->takeControlState(control.name(), control.type()); if (it->value->isEmpty()) m_savedFormStateMap.remove(it); return state; }
void FormController::restoreControlStateIn(HTMLFormElement& form) { for (auto& element : form.associatedElements()) { if (!element->isFormControlElementWithState()) continue; HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(element); if (!control->shouldSaveAndRestoreFormControlState()) continue; if (ownerFormForState(*control) != &form) continue; FormControlState state = takeStateForFormElement(*control); if (state.valueSize() > 0) control->restoreFormControlState(state); } }
OwnPtr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormElementListHashSet& controlList) { OwnPtr<FormKeyGenerator> keyGenerator = FormKeyGenerator::create(); OwnPtr<SavedFormStateMap> stateMap = adoptPtr(new SavedFormStateMap); for (FormElementListHashSet::const_iterator it = controlList.begin(); it != controlList.end(); ++it) { HTMLFormControlElementWithState* control = it->get(); if (!control->shouldSaveAndRestoreFormControlState()) continue; SavedFormStateMap::AddResult result = stateMap->add(keyGenerator->formKey(*control).impl(), nullptr); if (result.isNewEntry) result.iterator->value = SavedFormState::create(); result.iterator->value->appendControlState(control->name(), control->type(), control->saveFormControlState()); } return stateMap.release(); }
std::unique_ptr<FormController::SavedFormStateMap> FormController::createSavedFormStateMap(const FormElementListHashSet& controlList) { FormKeyGenerator keyGenerator; auto stateMap = std::make_unique<SavedFormStateMap>(); for (FormElementListHashSet::const_iterator it = controlList.begin(); it != controlList.end(); ++it) { HTMLFormControlElementWithState* control = it->get(); if (!control->shouldSaveAndRestoreFormControlState()) continue; auto& formState = stateMap->add(keyGenerator.formKey(*control).impl(), nullptr).iterator->value; if (!formState) formState = std::make_unique<SavedFormState>(); formState->appendControlState(control->name(), control->type(), control->saveFormControlState()); } return stateMap; }
void FormController::restoreControlStateIn(HTMLFormElement& form) { const Vector<FormAssociatedElement*>& elements = form.associatedElements(); for (size_t i = 0; i < elements.size(); ++i) { if (!elements[i]->isFormControlElementWithState()) continue; HTMLFormControlElementWithState* control = static_cast<HTMLFormControlElementWithState*>(elements[i]); if (!control->shouldSaveAndRestoreFormControlState()) continue; if (ownerFormForState(*control) != &form) continue; FormControlState state = takeStateForFormElement(*control); if (state.valueSize() > 0) control->restoreFormControlState(state); } }
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.appendLiteral(" ["); 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(']'); }