1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
6 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB.  If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "HTMLFormElement.h"
27
28#include "Attribute.h"
29#include "DOMFormData.h"
30#include "DOMWindow.h"
31#include "Document.h"
32#include "Event.h"
33#include "EventNames.h"
34#include "FileList.h"
35#include "FileSystem.h"
36#include "FormController.h"
37#include "FormData.h"
38#include "FormDataList.h"
39#include "FormState.h"
40#include "Frame.h"
41#include "FrameLoader.h"
42#include "FrameLoaderClient.h"
43#include "HTMLCollection.h"
44#include "HTMLDocument.h"
45#include "HTMLImageElement.h"
46#include "HTMLInputElement.h"
47#include "HTMLNames.h"
48#include "MIMETypeRegistry.h"
49#include "NodeRenderingContext.h"
50#include "NodeTraversal.h"
51#include "Page.h"
52#include "RenderTextControl.h"
53#include "ScriptController.h"
54#include "ScriptEventListener.h"
55#include "Settings.h"
56#include "ValidityState.h"
57#include <limits>
58
59using namespace std;
60
61namespace WebCore {
62
63using namespace HTMLNames;
64
65HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
66    : HTMLElement(tagName, document)
67    , m_associatedElementsBeforeIndex(0)
68    , m_associatedElementsAfterIndex(0)
69    , m_wasUserSubmitted(false)
70    , m_isSubmittingOrPreparingForSubmission(false)
71    , m_shouldSubmit(false)
72    , m_isInResetFunction(false)
73    , m_wasDemoted(false)
74{
75    ASSERT(hasTagName(formTag));
76}
77
78PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
79{
80    return adoptRef(new HTMLFormElement(formTag, document));
81}
82
83PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
84{
85    return adoptRef(new HTMLFormElement(tagName, document));
86}
87
88HTMLFormElement::~HTMLFormElement()
89{
90    document()->formController().willDeleteForm(this);
91    if (!shouldAutocomplete())
92        document()->unregisterForPageCacheSuspensionCallbacks(this);
93
94    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
95        m_associatedElements[i]->formWillBeDestroyed();
96    for (unsigned i = 0; i < m_imageElements.size(); ++i)
97        m_imageElements[i]->m_form = 0;
98}
99
100bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
101{
102    return document()->completeURL(url).protocolIs("https");
103}
104
105bool HTMLFormElement::rendererIsNeeded(const NodeRenderingContext& context)
106{
107    if (!m_wasDemoted)
108        return HTMLElement::rendererIsNeeded(context);
109
110    ContainerNode* node = parentNode();
111    RenderObject* parentRenderer = node->renderer();
112    // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
113    bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
114        || (parentRenderer->isTableRow() && node->hasTagName(trTag))
115        || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
116        || (parentRenderer->isRenderTableCol() && node->hasTagName(colTag))
117        || (parentRenderer->isTableCell() && node->hasTagName(trTag));
118
119    if (!parentIsTableElementPart)
120        return true;
121
122    EDisplay display = context.style()->display();
123    bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
124        || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
125        || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
126        || display == TABLE_CAPTION;
127
128    return formIsTablePart;
129}
130
131Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
132{
133    HTMLElement::insertedInto(insertionPoint);
134    if (insertionPoint->inDocument())
135        this->document()->didAssociateFormControl(this);
136    return InsertionDone;
137}
138
139static inline Node* findRoot(Node* n)
140{
141    Node* root = n;
142    for (; n; n = n->parentNode())
143        root = n;
144    return root;
145}
146
147void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
148{
149    Node* root = findRoot(this);
150    Vector<FormAssociatedElement*> associatedElements(m_associatedElements);
151    for (unsigned i = 0; i < associatedElements.size(); ++i)
152        associatedElements[i]->formRemovedFromTree(root);
153    HTMLElement::removedFrom(insertionPoint);
154}
155
156void HTMLFormElement::handleLocalEvents(Event* event)
157{
158    Node* targetNode = event->target()->toNode();
159    if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
160        event->stopPropagation();
161        return;
162    }
163    HTMLElement::handleLocalEvents(event);
164}
165
166unsigned HTMLFormElement::length() const
167{
168    unsigned len = 0;
169    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
170        if (m_associatedElements[i]->isEnumeratable())
171            ++len;
172    return len;
173}
174
175Node* HTMLFormElement::item(unsigned index)
176{
177    return elements()->item(index);
178}
179
180void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
181{
182    int submissionTriggerCount = 0;
183    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
184        FormAssociatedElement* formAssociatedElement = m_associatedElements[i];
185        if (!formAssociatedElement->isFormControlElement())
186            continue;
187        HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(formAssociatedElement);
188        if (formElement->isSuccessfulSubmitButton()) {
189            if (formElement->renderer()) {
190                formElement->dispatchSimulatedClick(event);
191                return;
192            }
193        } else if (formElement->canTriggerImplicitSubmission())
194            ++submissionTriggerCount;
195    }
196    if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
197        prepareForSubmission(event);
198}
199
200static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
201{
202    for (Node* node = event->target()->toNode(); node; node = node->parentNode()) {
203        if (node->isElementNode() && toElement(node)->isFormControlElement())
204            return static_cast<HTMLFormControlElement*>(node);
205    }
206    return 0;
207}
208
209bool HTMLFormElement::validateInteractively(Event* event)
210{
211    ASSERT(event);
212    if (!document()->page() || !document()->page()->settings()->interactiveFormValidationEnabled() || noValidate())
213        return true;
214
215    HTMLFormControlElement* submitElement = submitElementFromEvent(event);
216    if (submitElement && submitElement->formNoValidate())
217        return true;
218
219    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
220        if (m_associatedElements[i]->isFormControlElement())
221            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->hideVisibleValidationMessage();
222    }
223
224    Vector<RefPtr<FormAssociatedElement> > unhandledInvalidControls;
225    if (!checkInvalidControlsAndCollectUnhandled(unhandledInvalidControls))
226        return true;
227    // Because the form has invalid controls, we abort the form submission and
228    // show a validation message on a focusable form control.
229
230    // Needs to update layout now because we'd like to call isFocusable(), which
231    // has !renderer()->needsLayout() assertion.
232    document()->updateLayoutIgnorePendingStylesheets();
233
234    RefPtr<HTMLFormElement> protector(this);
235    // Focus on the first focusable control and show a validation message.
236    for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
237        FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
238        HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
239        if (unhandled->isFocusable() && unhandled->inDocument()) {
240            unhandled->scrollIntoViewIfNeeded(false);
241            unhandled->focus();
242            if (unhandled->isFormControlElement())
243                static_cast<HTMLFormControlElement*>(unhandled)->updateVisibleValidationMessage();
244            break;
245        }
246    }
247    // Warn about all of unfocusable controls.
248    if (document()->frame()) {
249        for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
250            FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
251            HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
252            if (unhandled->isFocusable() && unhandled->inDocument())
253                continue;
254            String message("An invalid form control with name='%name' is not focusable.");
255            message.replace("%name", unhandledAssociatedElement->name());
256            document()->addConsoleMessage(RenderingMessageSource, ErrorMessageLevel, message);
257        }
258    }
259    return false;
260}
261
262bool HTMLFormElement::prepareForSubmission(Event* event)
263{
264    Frame* frame = document()->frame();
265    if (m_isSubmittingOrPreparingForSubmission || !frame)
266        return m_isSubmittingOrPreparingForSubmission;
267
268    m_isSubmittingOrPreparingForSubmission = true;
269    m_shouldSubmit = false;
270
271    // Interactive validation must be done before dispatching the submit event.
272    if (!validateInteractively(event)) {
273        m_isSubmittingOrPreparingForSubmission = false;
274        return false;
275    }
276
277    StringPairVector controlNamesAndValues;
278    getTextFieldValues(controlNamesAndValues);
279    RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), NotSubmittedByJavaScript);
280    frame->loader()->client()->dispatchWillSendSubmitEvent(formState.release());
281
282    RefPtr<HTMLFormElement> protect(this);
283    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
284        m_shouldSubmit = true;
285
286    m_isSubmittingOrPreparingForSubmission = false;
287
288    if (m_shouldSubmit)
289        submit(event, true, true, NotSubmittedByJavaScript);
290
291    return m_shouldSubmit;
292}
293
294void HTMLFormElement::submit()
295{
296    submit(0, false, true, NotSubmittedByJavaScript);
297}
298
299void HTMLFormElement::submitFromJavaScript()
300{
301    submit(0, false, ScriptController::processingUserGesture(), SubmittedByJavaScript);
302}
303
304void HTMLFormElement::getTextFieldValues(StringPairVector& fieldNamesAndValues) const
305{
306    ASSERT_ARG(fieldNamesAndValues, fieldNamesAndValues.isEmpty());
307
308    fieldNamesAndValues.reserveCapacity(m_associatedElements.size());
309    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
310        FormAssociatedElement* control = m_associatedElements[i];
311        HTMLElement* element = toHTMLElement(control);
312        if (!element->hasLocalName(inputTag))
313            continue;
314
315        HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
316        if (!input->isTextField())
317            continue;
318
319        fieldNamesAndValues.append(make_pair(input->name().string(), input->value()));
320    }
321}
322
323void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
324{
325    FrameView* view = document()->view();
326    Frame* frame = document()->frame();
327    if (!view || !frame)
328        return;
329
330    if (m_isSubmittingOrPreparingForSubmission) {
331        m_shouldSubmit = true;
332        return;
333    }
334
335    m_isSubmittingOrPreparingForSubmission = true;
336    m_wasUserSubmitted = processingUserGesture;
337
338    RefPtr<HTMLFormControlElement> firstSuccessfulSubmitButton;
339    bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
340
341    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
342        FormAssociatedElement* associatedElement = m_associatedElements[i];
343        if (!associatedElement->isFormControlElement())
344            continue;
345        if (needButtonActivation) {
346            HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(associatedElement);
347            if (control->isActivatedSubmit())
348                needButtonActivation = false;
349            else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
350                firstSuccessfulSubmitButton = control;
351        }
352    }
353
354    if (needButtonActivation && firstSuccessfulSubmitButton)
355        firstSuccessfulSubmitButton->setActivatedSubmit(true);
356
357    bool lockHistory = !processingUserGesture;
358    RefPtr<HTMLFormElement> protect(this); // Form submission can execute arbitary JavaScript.
359    frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, lockHistory, formSubmissionTrigger));
360
361    if (needButtonActivation && firstSuccessfulSubmitButton)
362        firstSuccessfulSubmitButton->setActivatedSubmit(false);
363
364    m_shouldSubmit = false;
365    m_isSubmittingOrPreparingForSubmission = false;
366}
367
368void HTMLFormElement::reset()
369{
370    Frame* frame = document()->frame();
371    if (m_isInResetFunction || !frame)
372        return;
373
374    m_isInResetFunction = true;
375
376    if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
377        m_isInResetFunction = false;
378        return;
379    }
380
381    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
382        if (m_associatedElements[i]->isFormControlElement())
383            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
384    }
385
386    m_isInResetFunction = false;
387}
388
389void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
390{
391    if (name == actionAttr)
392        m_attributes.parseAction(value);
393    else if (name == targetAttr)
394        m_attributes.setTarget(value);
395    else if (name == methodAttr)
396        m_attributes.updateMethodType(value);
397    else if (name == enctypeAttr)
398        m_attributes.updateEncodingType(value);
399    else if (name == accept_charsetAttr)
400        m_attributes.setAcceptCharset(value);
401    else if (name == autocompleteAttr) {
402        if (!shouldAutocomplete())
403            document()->registerForPageCacheSuspensionCallbacks(this);
404        else
405            document()->unregisterForPageCacheSuspensionCallbacks(this);
406    }
407    else
408        HTMLElement::parseAttribute(name, value);
409}
410
411template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
412{
413    size_t size = vec.size();
414    for (size_t i = 0; i != size; ++i)
415        if (vec[i] == item) {
416            vec.remove(i);
417            break;
418        }
419}
420
421unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, unsigned rangeStart, unsigned rangeEnd)
422{
423    if (m_associatedElements.isEmpty())
424        return 0;
425
426    ASSERT(rangeStart <= rangeEnd);
427
428    if (rangeStart == rangeEnd)
429        return rangeStart;
430
431    unsigned left = rangeStart;
432    unsigned right = rangeEnd - 1;
433    unsigned short position;
434
435    // Does binary search on m_associatedElements in order to find the index
436    // to be inserted.
437    while (left != right) {
438        unsigned middle = left + ((right - left) / 2);
439        ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associatedElementsAfterIndex);
440        position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
441        if (position & DOCUMENT_POSITION_FOLLOWING)
442            right = middle;
443        else
444            left = middle + 1;
445    }
446
447    ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElementsAfterIndex);
448    position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
449    if (position & DOCUMENT_POSITION_FOLLOWING)
450        return left;
451    return left + 1;
452}
453
454unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
455{
456    HTMLElement* associatedHTMLElement = toHTMLElement(associatedElement);
457    // Treats separately the case where this element has the form attribute
458    // for performance consideration.
459    if (associatedHTMLElement->fastHasAttribute(formAttr)) {
460        unsigned short position = compareDocumentPosition(associatedHTMLElement);
461        if (position & DOCUMENT_POSITION_PRECEDING) {
462            ++m_associatedElementsBeforeIndex;
463            ++m_associatedElementsAfterIndex;
464            return HTMLFormElement::formElementIndexWithFormAttribute(associatedHTMLElement, 0, m_associatedElementsBeforeIndex - 1);
465        }
466        if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSITION_CONTAINED_BY))
467            return HTMLFormElement::formElementIndexWithFormAttribute(associatedHTMLElement, m_associatedElementsAfterIndex, m_associatedElements.size());
468    }
469
470    // Check for the special case where this element is the very last thing in
471    // the form's tree of children; we don't want to walk the entire tree in that
472    // common case that occurs during parsing; instead we'll just return a value
473    // that says "add this form element to the end of the array".
474    if (ElementTraversal::next(associatedHTMLElement, this)) {
475        unsigned i = m_associatedElementsBeforeIndex;
476        for (Element* element = this; element; element = ElementTraversal::next(element, this)) {
477            if (element == associatedHTMLElement) {
478                ++m_associatedElementsAfterIndex;
479                return i;
480            }
481            if (!element->isFormControlElement() && !element->hasTagName(objectTag))
482                continue;
483            if (!element->isHTMLElement() || toHTMLElement(element)->form() != this)
484                continue;
485            ++i;
486        }
487    }
488    return m_associatedElementsAfterIndex++;
489}
490
491void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
492{
493    m_associatedElements.insert(formElementIndex(e), e);
494}
495
496void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
497{
498    unsigned index;
499    for (index = 0; index < m_associatedElements.size(); ++index) {
500        if (m_associatedElements[index] == e)
501            break;
502    }
503    ASSERT_WITH_SECURITY_IMPLICATION(index < m_associatedElements.size());
504    if (index < m_associatedElementsBeforeIndex)
505        --m_associatedElementsBeforeIndex;
506    if (index < m_associatedElementsAfterIndex)
507        --m_associatedElementsAfterIndex;
508    removeFromVector(m_associatedElements, e);
509}
510
511bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
512{
513    return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
514}
515
516void HTMLFormElement::registerImgElement(HTMLImageElement* e)
517{
518    ASSERT(m_imageElements.find(e) == notFound);
519    m_imageElements.append(e);
520}
521
522void HTMLFormElement::removeImgElement(HTMLImageElement* e)
523{
524    ASSERT(m_imageElements.find(e) != notFound);
525    removeFromVector(m_imageElements, e);
526}
527
528PassRefPtr<HTMLCollection> HTMLFormElement::elements()
529{
530    return ensureCachedHTMLCollection(FormControls);
531}
532
533String HTMLFormElement::name() const
534{
535    return getNameAttribute();
536}
537
538bool HTMLFormElement::noValidate() const
539{
540    return fastHasAttribute(novalidateAttr);
541}
542
543// FIXME: This function should be removed because it does not do the same thing as the
544// JavaScript binding for action, which treats action as a URL attribute. Last time I
545// (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
546String HTMLFormElement::action() const
547{
548    return getAttribute(actionAttr);
549}
550
551void HTMLFormElement::setAction(const String &value)
552{
553    setAttribute(actionAttr, value);
554}
555
556void HTMLFormElement::setEnctype(const String &value)
557{
558    setAttribute(enctypeAttr, value);
559}
560
561String HTMLFormElement::method() const
562{
563    return FormSubmission::Attributes::methodString(m_attributes.method());
564}
565
566void HTMLFormElement::setMethod(const String &value)
567{
568    setAttribute(methodAttr, value);
569}
570
571String HTMLFormElement::target() const
572{
573    return getAttribute(targetAttr);
574}
575
576bool HTMLFormElement::wasUserSubmitted() const
577{
578    return m_wasUserSubmitted;
579}
580
581HTMLFormControlElement* HTMLFormElement::defaultButton() const
582{
583    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
584        if (!m_associatedElements[i]->isFormControlElement())
585            continue;
586        HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(m_associatedElements[i]);
587        if (control->isSuccessfulSubmitButton())
588            return control;
589    }
590
591    return 0;
592}
593
594bool HTMLFormElement::checkValidity()
595{
596    Vector<RefPtr<FormAssociatedElement> > controls;
597    return !checkInvalidControlsAndCollectUnhandled(controls);
598}
599
600bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
601{
602    RefPtr<HTMLFormElement> protector(this);
603    // Copy m_associatedElements because event handlers called from
604    // HTMLFormControlElement::checkValidity() might change m_associatedElements.
605    Vector<RefPtr<FormAssociatedElement> > elements;
606    elements.reserveCapacity(m_associatedElements.size());
607    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
608        elements.append(m_associatedElements[i]);
609    bool hasInvalidControls = false;
610    for (unsigned i = 0; i < elements.size(); ++i) {
611        if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
612            HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(elements[i].get());
613            if (!control->checkValidity(&unhandledInvalidControls) && control->form() == this)
614                hasInvalidControls = true;
615        }
616    }
617    return hasInvalidControls;
618}
619
620HTMLFormControlElement* HTMLFormElement::elementForAlias(const AtomicString& alias)
621{
622    if (alias.isEmpty() || !m_elementAliases)
623        return 0;
624    return m_elementAliases->get(alias.impl());
625}
626
627void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
628{
629    if (alias.isEmpty())
630        return;
631    if (!m_elementAliases)
632        m_elementAliases = adoptPtr(new AliasMap);
633    m_elementAliases->set(alias.impl(), element);
634}
635
636void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
637{
638    elements()->namedItems(name, namedItems);
639
640    HTMLFormControlElement* aliasElement = elementForAlias(name);
641    if (aliasElement) {
642        if (namedItems.find(aliasElement) == notFound) {
643            // We have seen it before but it is gone now. Still, we need to return it.
644            // FIXME: The above comment is not clear enough; it does not say why we need to do this.
645            namedItems.append(aliasElement);
646        }
647    }
648    if (namedItems.size() && namedItems.first() != aliasElement)
649        addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
650}
651
652void HTMLFormElement::documentDidResumeFromPageCache()
653{
654    ASSERT(!shouldAutocomplete());
655
656    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
657        if (m_associatedElements[i]->isFormControlElement())
658            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
659    }
660}
661
662void HTMLFormElement::didMoveToNewDocument(Document* oldDocument)
663{
664    if (!shouldAutocomplete()) {
665        if (oldDocument)
666            oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
667        document()->registerForPageCacheSuspensionCallbacks(this);
668    }
669
670    HTMLElement::didMoveToNewDocument(oldDocument);
671}
672
673bool HTMLFormElement::shouldAutocomplete() const
674{
675    return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
676}
677
678void HTMLFormElement::finishParsingChildren()
679{
680    HTMLElement::finishParsingChildren();
681    document()->formController().restoreControlStateIn(*this);
682}
683
684void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
685{
686    m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
687    HTMLElement::copyNonAttributePropertiesFromElement(source);
688}
689
690} // namespace
691