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