Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/html/HTMLFormElement.h"
27
28 #include <limits>
29 #include "HTMLNames.h"
30 #include "bindings/v8/Dictionary.h"
31 #include "bindings/v8/ScriptController.h"
32 #include "bindings/v8/ScriptEventListener.h"
33 #include "core/dom/Attribute.h"
34 #include "core/dom/Document.h"
35 #include "core/dom/ElementTraversal.h"
36 #include "core/dom/IdTargetObserverRegistry.h"
37 #include "core/events/AutocompleteErrorEvent.h"
38 #include "core/events/Event.h"
39 #include "core/events/GenericEventQueue.h"
40 #include "core/events/ScopedEventQueue.h"
41 #include "core/html/HTMLCollection.h"
42 #include "core/html/HTMLDialogElement.h"
43 #include "core/html/HTMLImageElement.h"
44 #include "core/html/HTMLInputElement.h"
45 #include "core/html/HTMLObjectElement.h"
46 #include "core/html/RadioNodeList.h"
47 #include "core/html/forms/FormController.h"
48 #include "core/loader/FrameLoader.h"
49 #include "core/loader/FrameLoaderClient.h"
50 #include "core/frame/DOMWindow.h"
51 #include "core/frame/LocalFrame.h"
52 #include "core/frame/UseCounter.h"
53 #include "core/frame/csp/ContentSecurityPolicy.h"
54 #include "core/rendering/RenderTextControl.h"
55 #include "platform/UserGestureIndicator.h"
56
57 using namespace std;
58
59 namespace WebCore {
60
61 using namespace HTMLNames;
62
63 HTMLFormElement::HTMLFormElement(Document& document)
64     : HTMLElement(formTag, document)
65     , m_weakPtrFactory(this)
66     , m_associatedElementsAreDirty(false)
67     , m_imageElementsAreDirty(false)
68     , m_hasElementsAssociatedByParser(false)
69     , m_didFinishParsingChildren(false)
70     , m_wasUserSubmitted(false)
71     , m_isInResetFunction(false)
72     , m_wasDemoted(false)
73     , m_pendingAutocompleteEventsQueue(GenericEventQueue::create(this))
74 {
75     ScriptWrappable::init(this);
76 }
77
78 PassRefPtrWillBeRawPtr<HTMLFormElement> HTMLFormElement::create(Document& document)
79 {
80     UseCounter::count(document, UseCounter::FormElement);
81     return adoptRefWillBeRefCountedGarbageCollected(new HTMLFormElement(document));
82 }
83
84 HTMLFormElement::~HTMLFormElement()
85 {
86 #if !ENABLE(OILPAN)
87     // With Oilpan, either removedFrom is called or the document and
88     // form controller are dead as well and there is no need to remove
89     // this form element from it.
90     document().formController().willDeleteForm(this);
91 #endif
92 }
93
94 void HTMLFormElement::trace(Visitor* visitor)
95 {
96 #if ENABLE(OILPAN)
97     visitor->trace(m_pastNamesMap);
98     visitor->trace(m_associatedElements);
99 #endif
100     HTMLElement::trace(visitor);
101 }
102
103 bool HTMLFormElement::rendererIsNeeded(const RenderStyle& style)
104 {
105     if (!m_wasDemoted)
106         return HTMLElement::rendererIsNeeded(style);
107
108     ContainerNode* node = parentNode();
109     if (!node || !node->renderer())
110         return HTMLElement::rendererIsNeeded(style);
111     RenderObject* parentRenderer = node->renderer();
112     // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
113     // FIXME: This check is not correct for Shadow DOM.
114     bool parentIsTableElementPart = (parentRenderer->isTable() && isHTMLTableElement(*node))
115         || (parentRenderer->isTableRow() && isHTMLTableRowElement(*node))
116         || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
117         || (parentRenderer->isRenderTableCol() && node->hasTagName(colTag))
118         || (parentRenderer->isTableCell() && isHTMLTableRowElement(*node));
119
120     if (!parentIsTableElementPart)
121         return true;
122
123     EDisplay display = style.display();
124     bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
125         || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
126         || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
127         || display == TABLE_CAPTION;
128
129     return formIsTablePart;
130 }
131
132 Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
133 {
134     HTMLElement::insertedInto(insertionPoint);
135     if (insertionPoint->inDocument())
136         this->document().didAssociateFormControl(this);
137     return InsertionDone;
138 }
139
140 template<class T>
141 void notifyFormRemovedFromTree(const T& elements, Node& root)
142 {
143     size_t size = elements.size();
144     for (size_t i = 0; i < size; ++i)
145         elements[i]->formRemovedFromTree(root);
146     ASSERT(elements.size() == size);
147 }
148
149 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
150 {
151     // We don't need to take care of form association by 'form' content
152     // attribute becuse IdTargetObserver handles it.
153     if (m_hasElementsAssociatedByParser) {
154         Node& root = highestAncestorOrSelf();
155         if (!m_associatedElementsAreDirty) {
156             FormAssociatedElement::List elements(associatedElements());
157             notifyFormRemovedFromTree(elements, root);
158         } else {
159             FormAssociatedElement::List elements;
160             collectAssociatedElements(insertionPoint->highestAncestorOrSelf(), elements);
161             notifyFormRemovedFromTree(elements, root);
162             collectAssociatedElements(root, elements);
163             notifyFormRemovedFromTree(elements, root);
164         }
165
166         if (!m_imageElementsAreDirty) {
167             Vector<HTMLImageElement*> images(imageElements());
168             notifyFormRemovedFromTree(images, root);
169         } else {
170             Vector<HTMLImageElement*> images;
171             collectImageElements(insertionPoint->highestAncestorOrSelf(), images);
172             notifyFormRemovedFromTree(images, root);
173             collectImageElements(root, images);
174             notifyFormRemovedFromTree(images, root);
175         }
176     }
177 #if ENABLE(OILPAN)
178     document().formController().willDeleteForm(this);
179 #endif
180     HTMLElement::removedFrom(insertionPoint);
181 }
182
183 void HTMLFormElement::handleLocalEvents(Event* event)
184 {
185     Node* targetNode = event->target()->toNode();
186     if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == EventTypeNames::submit || event->type() == EventTypeNames::reset)) {
187         event->stopPropagation();
188         return;
189     }
190     HTMLElement::handleLocalEvents(event);
191 }
192
193 unsigned HTMLFormElement::length() const
194 {
195     const FormAssociatedElement::List& elements = associatedElements();
196     unsigned len = 0;
197     for (unsigned i = 0; i < elements.size(); ++i) {
198         if (elements[i]->isEnumeratable())
199             ++len;
200     }
201     return len;
202 }
203
204 Element* HTMLFormElement::item(unsigned index)
205 {
206     return elements()->item(index);
207 }
208
209 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
210 {
211     int submissionTriggerCount = 0;
212     bool seenDefaultButton = false;
213     const FormAssociatedElement::List& elements = associatedElements();
214     for (unsigned i = 0; i < elements.size(); ++i) {
215         FormAssociatedElement* formAssociatedElement = elements[i];
216         if (!formAssociatedElement->isFormControlElement())
217             continue;
218         HTMLFormControlElement* control = toHTMLFormControlElement(formAssociatedElement);
219         if (!seenDefaultButton && control->canBeSuccessfulSubmitButton()) {
220             if (fromImplicitSubmissionTrigger)
221                 seenDefaultButton = true;
222             if (control->isSuccessfulSubmitButton()) {
223                 control->dispatchSimulatedClick(event);
224                 return;
225             } else if (fromImplicitSubmissionTrigger) {
226                 // Default (submit) button is not activated; no implicit submission.
227                 return;
228             }
229         } else if (control->canTriggerImplicitSubmission()) {
230             ++submissionTriggerCount;
231         }
232     }
233     if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
234         prepareForSubmission(event);
235 }
236
237 // FIXME: Consolidate this and similar code in FormSubmission.cpp.
238 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
239 {
240     for (Node* node = event->target()->toNode(); node; node = node->parentOrShadowHostNode()) {
241         if (node->isElementNode() && toElement(node)->isFormControlElement())
242             return toHTMLFormControlElement(node);
243     }
244     return 0;
245 }
246
247 bool HTMLFormElement::validateInteractively(Event* event)
248 {
249     ASSERT(event);
250     if (!document().page() || noValidate())
251         return true;
252
253     HTMLFormControlElement* submitElement = submitElementFromEvent(event);
254     if (submitElement && submitElement->formNoValidate())
255         return true;
256
257     const FormAssociatedElement::List& elements = associatedElements();
258     for (unsigned i = 0; i < elements.size(); ++i) {
259         if (elements[i]->isFormControlElement())
260             toHTMLFormControlElement(elements[i])->hideVisibleValidationMessage();
261     }
262
263     WillBeHeapVector<RefPtrWillBeMember<FormAssociatedElement> > unhandledInvalidControls;
264     if (!checkInvalidControlsAndCollectUnhandled(&unhandledInvalidControls))
265         return true;
266     // Because the form has invalid controls, we abort the form submission and
267     // show a validation message on a focusable form control.
268
269     // Needs to update layout now because we'd like to call isFocusable(), which
270     // has !renderer()->needsLayout() assertion.
271     document().updateLayoutIgnorePendingStylesheets();
272
273     RefPtrWillBeRawPtr<HTMLFormElement> protector(this);
274     // Focus on the first focusable control and show a validation message.
275     for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
276         FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
277         HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
278         if (unhandled->isFocusable() && unhandled->inDocument()) {
279             unhandled->scrollIntoViewIfNeeded(false);
280             unhandled->focus();
281             if (unhandled->isFormControlElement())
282                 toHTMLFormControlElement(unhandled)->updateVisibleValidationMessage();
283             break;
284         }
285     }
286     // Warn about all of unfocusable controls.
287     if (document().frame()) {
288         for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
289             FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
290             HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
291             if (unhandled->isFocusable() && unhandled->inDocument())
292                 continue;
293             String message("An invalid form control with name='%name' is not focusable.");
294             message.replace("%name", unhandledAssociatedElement->name());
295             document().addConsoleMessage(RenderingMessageSource, ErrorMessageLevel, message);
296         }
297     }
298     return false;
299 }
300
301 void HTMLFormElement::prepareForSubmission(Event* event)
302 {
303     RefPtrWillBeRawPtr<HTMLFormElement> protector(this);
304     LocalFrame* frame = document().frame();
305     if (!frame)
306         return;
307
308     // Interactive validation must be done before dispatching the submit event.
309     if (!validateInteractively(event))
310         return;
311
312     frame->loader().client()->dispatchWillSendSubmitEvent(this);
313
314     if (dispatchEvent(Event::createCancelableBubble(EventTypeNames::submit)))
315         submit(event, true, true, NotSubmittedByJavaScript);
316 }
317
318 void HTMLFormElement::submit()
319 {
320     submit(0, false, true, NotSubmittedByJavaScript);
321 }
322
323 void HTMLFormElement::submitFromJavaScript()
324 {
325     submit(0, false, UserGestureIndicator::processingUserGesture(), SubmittedByJavaScript);
326 }
327
328 void HTMLFormElement::submitDialog(PassRefPtr<FormSubmission> formSubmission)
329 {
330     for (Node* node = this; node; node = node->parentOrShadowHostNode()) {
331         if (isHTMLDialogElement(*node)) {
332             toHTMLDialogElement(*node).closeDialog(formSubmission->result());
333             return;
334         }
335     }
336 }
337
338 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
339 {
340     FrameView* view = document().view();
341     LocalFrame* frame = document().frame();
342     if (!view || !frame || !frame->page())
343         return;
344
345     m_wasUserSubmitted = processingUserGesture;
346
347     RefPtrWillBeRawPtr<HTMLFormControlElement> firstSuccessfulSubmitButton = nullptr;
348     bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
349
350     const FormAssociatedElement::List& elements = associatedElements();
351     for (unsigned i = 0; i < elements.size(); ++i) {
352         FormAssociatedElement* associatedElement = elements[i];
353         if (!associatedElement->isFormControlElement())
354             continue;
355         if (needButtonActivation) {
356             HTMLFormControlElement* control = toHTMLFormControlElement(associatedElement);
357             if (control->isActivatedSubmit())
358                 needButtonActivation = false;
359             else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
360                 firstSuccessfulSubmitButton = control;
361         }
362     }
363
364     if (needButtonActivation && firstSuccessfulSubmitButton)
365         firstSuccessfulSubmitButton->setActivatedSubmit(true);
366
367     RefPtr<FormSubmission> formSubmission = FormSubmission::create(this, m_attributes, event, formSubmissionTrigger);
368     EventQueueScope scopeForDialogClose; // Delay dispatching 'close' to dialog until done submitting.
369     if (formSubmission->method() == FormSubmission::DialogMethod)
370         submitDialog(formSubmission.release());
371     else
372         scheduleFormSubmission(formSubmission.release());
373
374     if (needButtonActivation && firstSuccessfulSubmitButton)
375         firstSuccessfulSubmitButton->setActivatedSubmit(false);
376 }
377
378 void HTMLFormElement::scheduleFormSubmission(PassRefPtr<FormSubmission> submission)
379 {
380     ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
381     ASSERT(submission->data());
382     ASSERT(submission->state());
383     if (submission->action().isEmpty())
384         return;
385     if (document().isSandboxed(SandboxForms)) {
386         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
387         document().addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked form submission to '" + submission->action().elidedString() + "' because the form's frame is sandboxed and the 'allow-forms' permission is not set.");
388         return;
389     }
390
391     if (protocolIsJavaScript(submission->action())) {
392         if (!document().contentSecurityPolicy()->allowFormAction(KURL(submission->action())))
393             return;
394         document().frame()->script().executeScriptIfJavaScriptURL(submission->action());
395         return;
396     }
397
398     LocalFrame* targetFrame = document().frame()->loader().findFrameForNavigation(submission->target(), submission->state()->sourceDocument());
399     if (!targetFrame) {
400         if (!DOMWindow::allowPopUp(*document().frame()) && !UserGestureIndicator::processingUserGesture())
401             return;
402         targetFrame = document().frame();
403     } else {
404         submission->clearTarget();
405     }
406     if (!targetFrame->page())
407         return;
408
409     submission->setReferrer(Referrer(document().outgoingReferrer(), document().referrerPolicy()));
410     submission->setOrigin(document().outgoingOrigin());
411
412     targetFrame->navigationScheduler().scheduleFormSubmission(submission);
413 }
414
415 void HTMLFormElement::reset()
416 {
417     LocalFrame* frame = document().frame();
418     if (m_isInResetFunction || !frame)
419         return;
420
421     m_isInResetFunction = true;
422
423     if (!dispatchEvent(Event::createCancelableBubble(EventTypeNames::reset))) {
424         m_isInResetFunction = false;
425         return;
426     }
427
428     const FormAssociatedElement::List& elements = associatedElements();
429     for (unsigned i = 0; i < elements.size(); ++i) {
430         if (elements[i]->isFormControlElement())
431             toHTMLFormControlElement(elements[i])->reset();
432     }
433
434     m_isInResetFunction = false;
435 }
436
437 void HTMLFormElement::requestAutocomplete(const Dictionary& details)
438 {
439     String errorMessage;
440
441     if (!document().frame())
442         errorMessage = "requestAutocomplete: form is not owned by a displayed document.";
443     else if (!shouldAutocomplete())
444         errorMessage = "requestAutocomplete: form autocomplete attribute is set to off.";
445     else if (!UserGestureIndicator::processingUserGesture())
446         errorMessage = "requestAutocomplete: must be called in response to a user gesture.";
447
448     if (!errorMessage.isEmpty()) {
449         document().addConsoleMessage(RenderingMessageSource, LogMessageLevel, errorMessage);
450         finishRequestAutocomplete(AutocompleteResultErrorDisabled);
451     } else {
452         document().frame()->loader().client()->didRequestAutocomplete(this, details);
453     }
454 }
455
456 void HTMLFormElement::finishRequestAutocomplete(AutocompleteResult result)
457 {
458     RefPtrWillBeRawPtr<Event> event = nullptr;
459     if (result == AutocompleteResultSuccess)
460         event = Event::createBubble(EventTypeNames::autocomplete);
461     else if (result == AutocompleteResultErrorDisabled)
462         event = AutocompleteErrorEvent::create("disabled");
463     else if (result == AutocompleteResultErrorCancel)
464         event = AutocompleteErrorEvent::create("cancel");
465     else if (result == AutocompleteResultErrorInvalid)
466         event = AutocompleteErrorEvent::create("invalid");
467     else
468         ASSERT_NOT_REACHED();
469
470     event->setTarget(this);
471     m_pendingAutocompleteEventsQueue->enqueueEvent(event.release());
472 }
473
474 void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
475 {
476     if (name == actionAttr)
477         m_attributes.parseAction(value);
478     else if (name == targetAttr)
479         m_attributes.setTarget(value);
480     else if (name == methodAttr)
481         m_attributes.updateMethodType(value);
482     else if (name == enctypeAttr)
483         m_attributes.updateEncodingType(value);
484     else if (name == accept_charsetAttr)
485         m_attributes.setAcceptCharset(value);
486     else if (name == onautocompleteAttr)
487         setAttributeEventListener(EventTypeNames::autocomplete, createAttributeEventListener(this, name, value));
488     else if (name == onautocompleteerrorAttr)
489         setAttributeEventListener(EventTypeNames::autocompleteerror, createAttributeEventListener(this, name, value));
490     else
491         HTMLElement::parseAttribute(name, value);
492 }
493
494 void HTMLFormElement::associate(FormAssociatedElement& e)
495 {
496     m_associatedElementsAreDirty = true;
497     m_associatedElements.clear();
498 }
499
500 void HTMLFormElement::disassociate(FormAssociatedElement& e)
501 {
502     m_associatedElementsAreDirty = true;
503     m_associatedElements.clear();
504     removeFromPastNamesMap(toHTMLElement(e));
505 }
506
507 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
508 {
509     return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
510 }
511
512 bool HTMLFormElement::hasLegalLinkAttribute(const QualifiedName& name) const
513 {
514     return name == actionAttr || HTMLElement::hasLegalLinkAttribute(name);
515 }
516
517 void HTMLFormElement::associate(HTMLImageElement& e)
518 {
519     m_imageElementsAreDirty = true;
520     m_imageElements.clear();
521 }
522
523 void HTMLFormElement::disassociate(HTMLImageElement& e)
524 {
525     m_imageElementsAreDirty = true;
526     m_imageElements.clear();
527     removeFromPastNamesMap(e);
528 }
529
530 WeakPtr<HTMLFormElement> HTMLFormElement::createWeakPtr()
531 {
532     return m_weakPtrFactory.createWeakPtr();
533 }
534
535 void HTMLFormElement::didAssociateByParser()
536 {
537     if (!m_didFinishParsingChildren)
538         return;
539     m_hasElementsAssociatedByParser = true;
540     UseCounter::count(document(), UseCounter::FormAssociationByParser);
541 }
542
543 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
544 {
545     return ensureCachedHTMLCollection(FormControls);
546 }
547
548 void HTMLFormElement::collectAssociatedElements(Node& root, FormAssociatedElement::List& elements) const
549 {
550     elements.clear();
551     for (HTMLElement* element = Traversal<HTMLElement>::firstWithin(root); element; element = Traversal<HTMLElement>::next(*element)) {
552         FormAssociatedElement* associatedElement = 0;
553         if (element->isFormControlElement())
554             associatedElement = toHTMLFormControlElement(element);
555         else if (isHTMLObjectElement(*element))
556             associatedElement = toHTMLObjectElement(element);
557         else
558             continue;
559         if (associatedElement->form()== this)
560             elements.append(associatedElement);
561     }
562 }
563
564 // This function should be const conceptually. However we update some fields
565 // because of lazy evaluation.
566 const FormAssociatedElement::List& HTMLFormElement::associatedElements() const
567 {
568     if (!m_associatedElementsAreDirty)
569         return m_associatedElements;
570     HTMLFormElement* mutableThis = const_cast<HTMLFormElement*>(this);
571     Node* scope = mutableThis;
572     if (m_hasElementsAssociatedByParser)
573         scope = &highestAncestorOrSelf();
574     if (inDocument() && treeScope().idTargetObserverRegistry().hasObservers(fastGetAttribute(idAttr)))
575         scope = &treeScope().rootNode();
576     ASSERT(scope);
577     collectAssociatedElements(*scope, mutableThis->m_associatedElements);
578     mutableThis->m_associatedElementsAreDirty = false;
579     return m_associatedElements;
580 }
581
582 void HTMLFormElement::collectImageElements(Node& root, Vector<HTMLImageElement*>& elements)
583 {
584     elements.clear();
585     for (HTMLImageElement* image = Traversal<HTMLImageElement>::firstWithin(root); image; image = Traversal<HTMLImageElement>::next(*image)) {
586         if (image->formOwner() == this)
587             elements.append(image);
588     }
589 }
590
591 const Vector<HTMLImageElement*>& HTMLFormElement::imageElements()
592 {
593     if (!m_imageElementsAreDirty)
594         return m_imageElements;
595     collectImageElements(m_hasElementsAssociatedByParser ? highestAncestorOrSelf() : *this, m_imageElements);
596     m_imageElementsAreDirty = false;
597     return m_imageElements;
598 }
599
600 String HTMLFormElement::name() const
601 {
602     return getNameAttribute();
603 }
604
605 bool HTMLFormElement::noValidate() const
606 {
607     return fastHasAttribute(novalidateAttr);
608 }
609
610 // FIXME: This function should be removed because it does not do the same thing as the
611 // JavaScript binding for action, which treats action as a URL attribute. Last time I
612 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
613 const AtomicString& HTMLFormElement::action() const
614 {
615     return getAttribute(actionAttr);
616 }
617
618 void HTMLFormElement::setEnctype(const AtomicString& value)
619 {
620     setAttribute(enctypeAttr, value);
621 }
622
623 String HTMLFormElement::method() const
624 {
625     return FormSubmission::Attributes::methodString(m_attributes.method());
626 }
627
628 void HTMLFormElement::setMethod(const AtomicString& value)
629 {
630     setAttribute(methodAttr, value);
631 }
632
633 bool HTMLFormElement::wasUserSubmitted() const
634 {
635     return m_wasUserSubmitted;
636 }
637
638 HTMLFormControlElement* HTMLFormElement::defaultButton() const
639 {
640     const FormAssociatedElement::List& elements = associatedElements();
641     for (unsigned i = 0; i < elements.size(); ++i) {
642         if (!elements[i]->isFormControlElement())
643             continue;
644         HTMLFormControlElement* control = toHTMLFormControlElement(elements[i]);
645         if (control->isSuccessfulSubmitButton())
646             return control;
647     }
648
649     return 0;
650 }
651
652 bool HTMLFormElement::checkValidity()
653 {
654     return !checkInvalidControlsAndCollectUnhandled(0);
655 }
656
657 bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(WillBeHeapVector<RefPtrWillBeMember<FormAssociatedElement> >* unhandledInvalidControls)
658 {
659     RefPtrWillBeRawPtr<HTMLFormElement> protector(this);
660     // Copy associatedElements because event handlers called from
661     // HTMLFormControlElement::checkValidity() might change associatedElements.
662     const FormAssociatedElement::List& associatedElements = this->associatedElements();
663     WillBeHeapVector<RefPtrWillBeMember<FormAssociatedElement> > elements;
664     elements.reserveCapacity(associatedElements.size());
665     for (unsigned i = 0; i < associatedElements.size(); ++i)
666         elements.append(associatedElements[i]);
667     bool hasInvalidControls = false;
668     for (unsigned i = 0; i < elements.size(); ++i) {
669         if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
670             HTMLFormControlElement* control = toHTMLFormControlElement(elements[i].get());
671             if (!control->checkValidity(unhandledInvalidControls) && control->formOwner() == this)
672                 hasInvalidControls = true;
673         }
674     }
675     return hasInvalidControls;
676 }
677
678 Element* HTMLFormElement::elementFromPastNamesMap(const AtomicString& pastName)
679 {
680     if (pastName.isEmpty() || !m_pastNamesMap)
681         return 0;
682     Element* element = m_pastNamesMap->get(pastName);
683 #if !ASSERT_DISABLED
684     if (!element)
685         return 0;
686     ASSERT_WITH_SECURITY_IMPLICATION(toHTMLElement(element)->formOwner() == this);
687     if (isHTMLImageElement(*element)) {
688         ASSERT_WITH_SECURITY_IMPLICATION(imageElements().find(element) != kNotFound);
689     } else if (isHTMLObjectElement(*element)) {
690         ASSERT_WITH_SECURITY_IMPLICATION(associatedElements().find(toHTMLObjectElement(element)) != kNotFound);
691     } else {
692         ASSERT_WITH_SECURITY_IMPLICATION(associatedElements().find(toHTMLFormControlElement(element)) != kNotFound);
693     }
694 #endif
695     return element;
696 }
697
698 void HTMLFormElement::addToPastNamesMap(Element* element, const AtomicString& pastName)
699 {
700     if (pastName.isEmpty())
701         return;
702     if (!m_pastNamesMap)
703         m_pastNamesMap = adoptPtrWillBeNoop(new PastNamesMap);
704     m_pastNamesMap->set(pastName, element);
705 }
706
707 void HTMLFormElement::removeFromPastNamesMap(HTMLElement& element)
708 {
709     if (!m_pastNamesMap)
710         return;
711     PastNamesMap::iterator end = m_pastNamesMap->end();
712     for (PastNamesMap::iterator it = m_pastNamesMap->begin(); it != end; ++it) {
713         if (it->value.get() == &element) {
714             it->value = nullptr;
715             // Keep looping. Single element can have multiple names.
716         }
717     }
718 }
719
720 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Element> >& namedItems)
721 {
722     // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
723     elements()->namedItems(name, namedItems);
724
725     Element* elementFromPast = elementFromPastNamesMap(name);
726     if (namedItems.size() && namedItems.first() != elementFromPast) {
727         addToPastNamesMap(namedItems.first().get(), name);
728     } else if (elementFromPast && namedItems.isEmpty()) {
729         namedItems.append(elementFromPast);
730         UseCounter::count(document(), UseCounter::FormNameAccessForPastNamesMap);
731     }
732 }
733
734 bool HTMLFormElement::shouldAutocomplete() const
735 {
736     return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
737 }
738
739 void HTMLFormElement::finishParsingChildren()
740 {
741     HTMLElement::finishParsingChildren();
742     document().formController().restoreControlStateIn(*this);
743     m_didFinishParsingChildren = true;
744 }
745
746 void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
747 {
748     m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
749     HTMLElement::copyNonAttributePropertiesFromElement(source);
750 }
751
752 void HTMLFormElement::anonymousNamedGetter(const AtomicString& name, bool& returnValue0Enabled, RefPtr<RadioNodeList>& returnValue0, bool& returnValue1Enabled, RefPtr<Element>& returnValue1)
753 {
754     // Call getNamedElements twice, first time check if it has a value
755     // and let HTMLFormElement update its cache.
756     // See issue: 867404
757     {
758         Vector<RefPtr<Element> > elements;
759         getNamedElements(name, elements);
760         if (elements.isEmpty())
761             return;
762     }
763
764     // Second call may return different results from the first call,
765     // but if the first the size cannot be zero.
766     Vector<RefPtr<Element> > elements;
767     getNamedElements(name, elements);
768     ASSERT(!elements.isEmpty());
769
770     if (elements.size() == 1) {
771         returnValue1Enabled = true;
772         returnValue1 = elements.at(0);
773         return;
774     }
775
776     bool onlyMatchImg = !elements.isEmpty() && isHTMLImageElement(*elements.first());
777     returnValue0Enabled = true;
778     returnValue0 = radioNodeList(name, onlyMatchImg);
779 }
780
781 void HTMLFormElement::setDemoted(bool demoted)
782 {
783     if (demoted)
784         UseCounter::count(document(), UseCounter::DemotedFormElement);
785     m_wasDemoted = demoted;
786 }
787
788 } // namespace