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