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