REGRESSION (r243606): Interacting with date and time pickers hangs the UI process...
[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-2010, 2012-2016 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 "DOMFormData.h"
29 #include "DOMWindow.h"
30 #include "Document.h"
31 #include "ElementIterator.h"
32 #include "Event.h"
33 #include "EventNames.h"
34 #include "FormController.h"
35 #include "FormData.h"
36 #include "Frame.h"
37 #include "FrameLoader.h"
38 #include "FrameLoaderClient.h"
39 #include "HTMLFieldSetElement.h"
40 #include "HTMLFormControlsCollection.h"
41 #include "HTMLImageElement.h"
42 #include "HTMLInputElement.h"
43 #include "HTMLNames.h"
44 #include "HTMLObjectElement.h"
45 #include "HTMLTableElement.h"
46 #include "NodeRareData.h"
47 #include "Page.h"
48 #include "RadioNodeList.h"
49 #include "RenderTextControl.h"
50 #include "ScriptDisallowedScope.h"
51 #include "Settings.h"
52 #include "UserGestureIndicator.h"
53 #include <limits>
54 #include <wtf/IsoMallocInlines.h>
55 #include <wtf/Ref.h>
56 #include <wtf/SetForScope.h>
57
58 namespace WebCore {
59
60 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLFormElement);
61
62 using namespace HTMLNames;
63
64 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document& document)
65     : HTMLElement(tagName, document)
66 {
67     ASSERT(hasTagName(formTag));
68 }
69
70 Ref<HTMLFormElement> HTMLFormElement::create(Document& document)
71 {
72     return adoptRef(*new HTMLFormElement(formTag, document));
73 }
74
75 Ref<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().unregisterForDocumentSuspensionCallbacks(*this);
85
86     m_defaultButton = nullptr;
87     for (auto& associatedElement : m_associatedElements)
88         associatedElement->formWillBeDestroyed();
89     for (auto& imageElement : m_imageElements)
90         imageElement->m_form = nullptr;
91 }
92
93 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
94 {
95     return document().completeURL(url).protocolIs("https");
96 }
97
98 bool HTMLFormElement::rendererIsNeeded(const RenderStyle& style)
99 {
100     if (!m_wasDemoted)
101         return HTMLElement::rendererIsNeeded(style);
102
103     auto parent = parentNode();
104     auto parentRenderer = parent->renderer();
105
106     if (!parentRenderer)
107         return false;
108
109     // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
110     bool parentIsTableElementPart = (parentRenderer->isTable() && is<HTMLTableElement>(*parent))
111         || (parentRenderer->isTableRow() && parent->hasTagName(trTag))
112         || (parentRenderer->isTableSection() && parent->hasTagName(tbodyTag))
113         || (parentRenderer->isRenderTableCol() && parent->hasTagName(colTag))
114         || (parentRenderer->isTableCell() && parent->hasTagName(trTag));
115
116     if (!parentIsTableElementPart)
117         return true;
118
119     DisplayType display = style.display();
120     bool formIsTablePart = display == DisplayType::Table || display == DisplayType::InlineTable || display == DisplayType::TableRowGroup
121         || display == DisplayType::TableHeaderGroup || display == DisplayType::TableFooterGroup || display == DisplayType::TableRow
122         || display == DisplayType::TableColumnGroup || display == DisplayType::TableColumn || display == DisplayType::TableCell
123         || display == DisplayType::TableCaption;
124
125     return formIsTablePart;
126 }
127
128 Node::InsertedIntoAncestorResult HTMLFormElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
129 {
130     HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
131     if (insertionType.connectedToDocument)
132         document().didAssociateFormControl(*this);
133     return InsertedIntoAncestorResult::Done;
134 }
135
136 void HTMLFormElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
137 {
138     Node& root = traverseToRootNode(); // Do not rely on rootNode() because our IsInTreeScope is outdated.
139     Vector<FormAssociatedElement*> associatedElements(m_associatedElements);
140     for (auto& associatedElement : associatedElements)
141         associatedElement->formOwnerRemovedFromTree(root);
142     HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
143 }
144
145 void HTMLFormElement::handleLocalEvents(Event& event, EventInvokePhase phase)
146 {
147     if (event.eventPhase() != Event::CAPTURING_PHASE && is<Node>(event.target()) && event.target() != this && (event.type() == eventNames().submitEvent || event.type() == eventNames().resetEvent)) {
148         event.stopPropagation();
149         return;
150     }
151     HTMLElement::handleLocalEvents(event, phase);
152 }
153
154 unsigned HTMLFormElement::length() const
155 {
156     unsigned length = 0;
157     for (auto& associatedElement : m_associatedElements) {
158         if (associatedElement->isEnumeratable())
159             ++length;
160     }
161     return length;
162 }
163
164 HTMLElement* HTMLFormElement::item(unsigned index)
165 {
166     return elements()->item(index);
167 }
168
169 Optional<Variant<RefPtr<RadioNodeList>, RefPtr<Element>>> HTMLFormElement::namedItem(const AtomString& name)
170 {
171     auto namedItems = namedElements(name);
172
173     if (namedItems.isEmpty())
174         return WTF::nullopt;
175     if (namedItems.size() == 1)
176         return Variant<RefPtr<RadioNodeList>, RefPtr<Element>> { RefPtr<Element> { WTFMove(namedItems[0]) } };
177
178     return Variant<RefPtr<RadioNodeList>, RefPtr<Element>> { RefPtr<RadioNodeList> { radioNodeList(name) } };
179 }
180
181 Vector<AtomString> HTMLFormElement::supportedPropertyNames() const
182 {
183     // FIXME: Should be implemented (only needed for enumeration with includeDontEnumProperties mode
184     // since this class is annotated with LegacyUnenumerableNamedProperties).
185     return { };
186 }
187
188 void HTMLFormElement::submitImplicitly(Event& event, bool fromImplicitSubmissionTrigger)
189 {
190     unsigned submissionTriggerCount = 0;
191     for (auto& formAssociatedElement : m_associatedElements) {
192         if (!is<HTMLFormControlElement>(*formAssociatedElement))
193             continue;
194         HTMLFormControlElement& formElement = downcast<HTMLFormControlElement>(*formAssociatedElement);
195         if (formElement.isSuccessfulSubmitButton()) {
196             if (formElement.renderer()) {
197                 formElement.dispatchSimulatedClick(&event);
198                 return;
199             }
200         } else if (formElement.canTriggerImplicitSubmission())
201             ++submissionTriggerCount;
202     }
203
204     if (!submissionTriggerCount)
205         return;
206
207     // Older iOS apps using WebViews expect the behavior of auto submitting multi-input forms.
208     if (fromImplicitSubmissionTrigger && (submissionTriggerCount == 1 || document().settings().allowMultiElementImplicitSubmission()))
209         prepareForSubmission(event);
210 }
211
212 bool HTMLFormElement::validateInteractively()
213 {
214     for (auto& associatedElement : m_associatedElements) {
215         if (is<HTMLFormControlElement>(*associatedElement))
216             downcast<HTMLFormControlElement>(*associatedElement).hideVisibleValidationMessage();
217     }
218
219     Vector<RefPtr<HTMLFormControlElement>> unhandledInvalidControls;
220     if (!checkInvalidControlsAndCollectUnhandled(unhandledInvalidControls))
221         return true;
222     // Because the form has invalid controls, we abort the form submission and
223     // show a validation message on a focusable form control.
224
225     // Make sure layout is up-to-date in case we call isFocusable() (which
226     // has !renderer()->needsLayout() assertion).
227     ASSERT(!document().view() || !document().view()->needsLayout());
228
229     Ref<HTMLFormElement> protectedThis(*this);
230
231     // Focus on the first focusable control and show a validation message.
232     for (auto& control : unhandledInvalidControls) {
233         if (control->isConnected() && control->isFocusable()) {
234             control->focusAndShowValidationMessage();
235             break;
236         }
237     }
238
239     // Warn about all of unfocusable controls.
240     if (document().frame()) {
241         for (auto& control : unhandledInvalidControls) {
242             if (control->isConnected() && control->isFocusable())
243                 continue;
244             String message = makeString("An invalid form control with name='", control->name(), "' is not focusable.");
245             document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, message);
246         }
247     }
248
249     return false;
250 }
251
252 void HTMLFormElement::prepareForSubmission(Event& event)
253 {
254     if (!isConnected())
255         return;
256
257     RefPtr<Frame> frame = document().frame();
258     if (m_isSubmittingOrPreparingForSubmission || !frame)
259         return;
260
261     m_isSubmittingOrPreparingForSubmission = true;
262     m_shouldSubmit = false;
263
264     bool shouldValidate = document().page() && document().page()->settings().interactiveFormValidationEnabled() && !noValidate();
265
266     if (shouldValidate) {
267         auto submitElement = findSubmitButton(&event);
268         if (submitElement && submitElement->formNoValidate())
269             shouldValidate = false;
270     }
271
272     // Interactive validation must be done before dispatching the submit event.
273     if (shouldValidate && !validateInteractively()) {
274         m_isSubmittingOrPreparingForSubmission = false;
275         return;
276     }
277
278     auto targetFrame = frame->loader().findFrameForNavigation(effectiveTarget(&event), &document());
279     if (!targetFrame)
280         targetFrame = frame.get();
281     auto formState = FormState::create(*this, textFieldValues(), document(), NotSubmittedByJavaScript);
282     targetFrame->loader().client().dispatchWillSendSubmitEvent(WTFMove(formState));
283
284     auto protectedThis = makeRef(*this);
285
286     auto submitEvent = Event::create(eventNames().submitEvent, Event::CanBubble::Yes, Event::IsCancelable::Yes);
287     dispatchEvent(submitEvent);
288
289     // Event handling could have resulted in m_shouldSubmit becoming true as a side effect, too.
290     if (!submitEvent->defaultPrevented())
291         m_shouldSubmit = true;
292
293     m_isSubmittingOrPreparingForSubmission = false;
294
295     if (m_shouldSubmit)
296         submit(&event, true, true, NotSubmittedByJavaScript);
297 }
298
299 void HTMLFormElement::submit()
300 {
301     submit(nullptr, false, true, NotSubmittedByJavaScript);
302 }
303
304 void HTMLFormElement::submitFromJavaScript()
305 {
306     submit(nullptr, false, UserGestureIndicator::processingUserGesture(), SubmittedByJavaScript);
307 }
308
309 StringPairVector HTMLFormElement::textFieldValues() const
310 {
311     StringPairVector result;
312     result.reserveInitialCapacity(m_associatedElements.size());
313     for (auto& associatedElement : m_associatedElements) {
314         auto& element = associatedElement->asHTMLElement();
315         if (!is<HTMLInputElement>(element))
316             continue;
317         auto& input = downcast<HTMLInputElement>(element);
318         if (!input.isTextField())
319             continue;
320         result.uncheckedAppend({ input.name().string(), input.value() });
321     }
322     return result;
323 }
324
325 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
326 {
327     RefPtr<FrameView> view = document().view();
328     RefPtr<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     RefPtr<HTMLFormControlElement> firstSuccessfulSubmitButton;
341     bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
342
343     for (auto& associatedElement : m_associatedElements) {
344         if (!is<HTMLFormControlElement>(*associatedElement))
345             continue;
346         if (needButtonActivation) {
347             HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*associatedElement);
348             if (control.isActivatedSubmit())
349                 needButtonActivation = false;
350             else if (!firstSuccessfulSubmitButton && control.isSuccessfulSubmitButton())
351                 firstSuccessfulSubmitButton = &control;
352         }
353     }
354
355     if (needButtonActivation && firstSuccessfulSubmitButton)
356         firstSuccessfulSubmitButton->setActivatedSubmit(true);
357
358     auto protectedThis = makeRef(*this); // Form submission can execute arbitary JavaScript.
359
360     auto shouldLockHistory = processingUserGesture ? LockHistory::No : LockHistory::Yes;
361     frame->loader().submitForm(FormSubmission::create(*this, m_attributes, event, shouldLockHistory, formSubmissionTrigger));
362
363     if (needButtonActivation && firstSuccessfulSubmitButton)
364         firstSuccessfulSubmitButton->setActivatedSubmit(false);
365
366     m_shouldSubmit = false;
367     m_isSubmittingOrPreparingForSubmission = false;
368 }
369
370 void HTMLFormElement::reset()
371 {
372     if (m_isInResetFunction)
373         return;
374
375     RefPtr<Frame> protectedFrame = document().frame();
376     if (!protectedFrame)
377         return;
378
379     Ref<HTMLFormElement> protectedThis(*this);
380
381     SetForScope<bool> isInResetFunctionRestorer(m_isInResetFunction, true);
382
383     auto event = Event::create(eventNames().resetEvent, Event::CanBubble::Yes, Event::IsCancelable::Yes);
384     dispatchEvent(event);
385     if (!event->defaultPrevented())
386         resetAssociatedFormControlElements();
387 }
388
389 void HTMLFormElement::resetAssociatedFormControlElements()
390 {
391     // Event handling can cause associated elements to be added or deleted while iterating
392     // over this collection. Protect these elements until we are done notifying them of
393     // the reset operation.
394     Vector<Ref<HTMLFormControlElement>> associatedFormControlElements;
395     associatedFormControlElements.reserveInitialCapacity(m_associatedElements.size());
396     for (auto* element : m_associatedElements) {
397         if (is<HTMLFormControlElement>(element))
398             associatedFormControlElements.uncheckedAppend(*downcast<HTMLFormControlElement>(element));
399     }
400     
401     for (auto& associatedFormControlElement : associatedFormControlElements)
402         associatedFormControlElement->reset();
403 }
404
405 #if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
406
407 // FIXME: We should look to share this code with class HTMLFormControlElement instead of duplicating the logic.
408
409 bool HTMLFormElement::shouldAutocorrect() const
410 {
411     const AtomString& autocorrectValue = attributeWithoutSynchronization(autocorrectAttr);
412     if (!autocorrectValue.isEmpty())
413         return !equalLettersIgnoringASCIICase(autocorrectValue, "off");
414     if (RefPtr<HTMLFormElement> form = this->form())
415         return form->shouldAutocorrect();
416     return true;
417 }
418
419 #endif
420
421 void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomString& value)
422 {
423     if (name == actionAttr) {
424         m_attributes.parseAction(value);
425         
426         if (!m_attributes.action().isEmpty()) {
427             if (RefPtr<Frame> f = document().frame()) {
428                 Frame& topFrame = f->tree().top();
429                 topFrame.loader().mixedContentChecker().checkFormForMixedContent(topFrame.document()->securityOrigin(), document().completeURL(m_attributes.action()));
430             }
431         }
432     } else if (name == targetAttr)
433         m_attributes.setTarget(value);
434     else if (name == methodAttr)
435         m_attributes.updateMethodType(value);
436     else if (name == enctypeAttr)
437         m_attributes.updateEncodingType(value);
438     else if (name == accept_charsetAttr)
439         m_attributes.setAcceptCharset(value);
440     else if (name == autocompleteAttr) {
441         if (!shouldAutocomplete())
442             document().registerForDocumentSuspensionCallbacks(*this);
443         else
444             document().unregisterForDocumentSuspensionCallbacks(*this);
445     } else
446         HTMLElement::parseAttribute(name, value);
447 }
448
449 unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, unsigned rangeStart, unsigned rangeEnd)
450 {
451     if (m_associatedElements.isEmpty())
452         return 0;
453
454     ASSERT(rangeStart <= rangeEnd);
455
456     if (rangeStart == rangeEnd)
457         return rangeStart;
458
459     unsigned left = rangeStart;
460     unsigned right = rangeEnd - 1;
461     unsigned short position;
462
463     // Does binary search on m_associatedElements in order to find the index
464     // to be inserted.
465     while (left != right) {
466         unsigned middle = left + ((right - left) / 2);
467         ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associatedElementsAfterIndex);
468         position = element->compareDocumentPosition(m_associatedElements[middle]->asHTMLElement());
469         if (position & DOCUMENT_POSITION_FOLLOWING)
470             right = middle;
471         else
472             left = middle + 1;
473     }
474     
475     ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElementsAfterIndex);
476     position = element->compareDocumentPosition(m_associatedElements[left]->asHTMLElement());
477     if (position & DOCUMENT_POSITION_FOLLOWING)
478         return left;
479     return left + 1;
480 }
481
482 unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
483 {
484     ASSERT(associatedElement);
485
486     HTMLElement& associatedHTMLElement = associatedElement->asHTMLElement();
487
488     // Treats separately the case where this element has the form attribute
489     // for performance consideration.
490     if (associatedHTMLElement.hasAttributeWithoutSynchronization(formAttr) && associatedHTMLElement.isConnected()) {
491         unsigned short position = compareDocumentPosition(associatedHTMLElement);
492         ASSERT_WITH_SECURITY_IMPLICATION(!(position & DOCUMENT_POSITION_DISCONNECTED));
493         if (position & DOCUMENT_POSITION_PRECEDING) {
494             ++m_associatedElementsBeforeIndex;
495             ++m_associatedElementsAfterIndex;
496             return HTMLFormElement::formElementIndexWithFormAttribute(&associatedHTMLElement, 0, m_associatedElementsBeforeIndex - 1);
497         }
498         if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSITION_CONTAINED_BY))
499             return HTMLFormElement::formElementIndexWithFormAttribute(&associatedHTMLElement, m_associatedElementsAfterIndex, m_associatedElements.size());
500     }
501
502     unsigned currentAssociatedElementsAfterIndex = m_associatedElementsAfterIndex;
503     ++m_associatedElementsAfterIndex;
504
505     if (!associatedHTMLElement.isDescendantOf(*this))
506         return currentAssociatedElementsAfterIndex;
507
508     // Check for the special case where this element is the very last thing in
509     // the form's tree of children; we don't want to walk the entire tree in that
510     // common case that occurs during parsing; instead we'll just return a value
511     // that says "add this form element to the end of the array".
512     auto descendants = descendantsOfType<HTMLElement>(*this);
513     auto it = descendants.beginAt(associatedHTMLElement);
514     auto end = descendants.end();
515     if (++it == end)
516         return currentAssociatedElementsAfterIndex;
517
518     unsigned i = m_associatedElementsBeforeIndex;
519     for (auto& element : descendants) {
520         if (&element == &associatedHTMLElement)
521             return i;
522         if (!is<HTMLFormControlElement>(element) && !is<HTMLObjectElement>(element))
523             continue;
524         if (element.form() != this)
525             continue;
526         ++i;
527     }
528     return currentAssociatedElementsAfterIndex;
529 }
530
531 void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
532 {
533     m_associatedElements.insert(formElementIndex(e), e);
534
535     if (is<HTMLFormControlElement>(e)) {
536         HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*e);
537         if (control.isSuccessfulSubmitButton()) {
538             if (!m_defaultButton)
539                 control.invalidateStyleForSubtree();
540             else
541                 resetDefaultButton();
542         }
543     }
544 }
545
546 void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
547 {
548     unsigned index = m_associatedElements.find(e);
549     ASSERT_WITH_SECURITY_IMPLICATION(index < m_associatedElements.size());
550     if (index < m_associatedElementsBeforeIndex)
551         --m_associatedElementsBeforeIndex;
552     if (index < m_associatedElementsAfterIndex)
553         --m_associatedElementsAfterIndex;
554     removeFromPastNamesMap(e);
555     m_associatedElements.remove(index);
556
557     if (auto* nodeLists = this->nodeLists())
558         nodeLists->invalidateCaches();
559
560     if (e == m_defaultButton)
561         resetDefaultButton();
562 }
563
564 void HTMLFormElement::registerInvalidAssociatedFormControl(const HTMLFormControlElement& formControlElement)
565 {
566     ASSERT_WITH_MESSAGE(!is<HTMLFieldSetElement>(formControlElement), "FieldSet are never candidates for constraint validation.");
567     ASSERT(static_cast<const Element&>(formControlElement).matchesInvalidPseudoClass());
568
569     if (m_invalidAssociatedFormControls.computesEmpty())
570         invalidateStyleForSubtree();
571     m_invalidAssociatedFormControls.add(const_cast<HTMLFormControlElement&>(formControlElement));
572 }
573
574 void HTMLFormElement::removeInvalidAssociatedFormControlIfNeeded(const HTMLFormControlElement& formControlElement)
575 {
576     if (m_invalidAssociatedFormControls.remove(formControlElement)) {
577         if (m_invalidAssociatedFormControls.computesEmpty())
578             invalidateStyleForSubtree();
579     }
580 }
581
582 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
583 {
584     return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
585 }
586
587 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
588 {
589     ASSERT(m_imageElements.find(e) == notFound);
590     m_imageElements.append(makeWeakPtr(e));
591 }
592
593 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
594 {
595     removeFromPastNamesMap(e);
596     bool removed = m_imageElements.removeFirst(e);
597     ASSERT_UNUSED(removed, removed);
598 }
599
600 Ref<HTMLFormControlsCollection> HTMLFormElement::elements()
601 {
602     return ensureRareData().ensureNodeLists().addCachedCollection<HTMLFormControlsCollection>(*this, FormControls);
603 }
604
605 Ref<HTMLCollection> HTMLFormElement::elementsForNativeBindings()
606 {
607     return elements();
608 }
609
610 String HTMLFormElement::name() const
611 {
612     return getNameAttribute();
613 }
614
615 bool HTMLFormElement::noValidate() const
616 {
617     return hasAttributeWithoutSynchronization(novalidateAttr);
618 }
619
620 // FIXME: This function should be removed because it does not do the same thing as the
621 // JavaScript binding for action, which treats action as a URL attribute. Last time I
622 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
623 String HTMLFormElement::action() const
624 {
625     return attributeWithoutSynchronization(actionAttr);
626 }
627
628 void HTMLFormElement::setAction(const String &value)
629 {
630     setAttributeWithoutSynchronization(actionAttr, value);
631 }
632
633 void HTMLFormElement::setEnctype(const String &value)
634 {
635     setAttributeWithoutSynchronization(enctypeAttr, value);
636 }
637
638 String HTMLFormElement::method() const
639 {
640     return FormSubmission::Attributes::methodString(m_attributes.method());
641 }
642
643 void HTMLFormElement::setMethod(const String &value)
644 {
645     setAttributeWithoutSynchronization(methodAttr, value);
646 }
647
648 String HTMLFormElement::target() const
649 {
650     return attributeWithoutSynchronization(targetAttr);
651 }
652
653 String HTMLFormElement::effectiveTarget(const Event* event) const
654 {
655     if (auto* submitButton = findSubmitButton(event)) {
656         auto targetValue = submitButton->attributeWithoutSynchronization(formtargetAttr);
657         if (!targetValue.isNull())
658             return targetValue;
659     }
660
661     auto targetValue = target();
662     if (!targetValue.isNull())
663         return targetValue;
664
665     return document().baseTarget();
666 }
667
668 bool HTMLFormElement::wasUserSubmitted() const
669 {
670     return m_wasUserSubmitted;
671 }
672
673 HTMLFormControlElement* HTMLFormElement::findSubmitButton(const Event* event) const
674 {
675     if (!event || !is<Node>(event->target()))
676         return nullptr;
677     auto& node = downcast<Node>(*event->target());
678     auto* element = is<Element>(node) ? &downcast<Element>(node) : node.parentElement();
679     return element ? lineageOfType<HTMLFormControlElement>(*element).first() : nullptr;
680 }
681
682 HTMLFormControlElement* HTMLFormElement::defaultButton() const
683 {
684     if (m_defaultButton)
685         return m_defaultButton.get();
686     for (auto& associatedElement : m_associatedElements) {
687         if (!is<HTMLFormControlElement>(*associatedElement))
688             continue;
689         HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*associatedElement);
690         if (control.isSuccessfulSubmitButton()) {
691             m_defaultButton = makeWeakPtr(control);
692             return &control;
693         }
694     }
695     return nullptr;
696 }
697
698 void HTMLFormElement::resetDefaultButton()
699 {
700     if (!m_defaultButton) {
701         // Computing the default button is not cheap, we don't want to do it unless needed.
702         // If there was no default button set, the only style to invalidate is the element
703         // being added to the form. This is done explicitely in registerFormElement().
704         return;
705     }
706
707     ScriptDisallowedScope::InMainThread scriptDisallowedScope;
708
709     auto oldDefault = WTFMove(m_defaultButton);
710     defaultButton();
711     if (m_defaultButton != oldDefault) {
712         if (oldDefault)
713             oldDefault->invalidateStyleForSubtree();
714         if (m_defaultButton)
715             m_defaultButton->invalidateStyleForSubtree();
716     }
717 }
718
719 bool HTMLFormElement::checkValidity()
720 {
721     Vector<RefPtr<HTMLFormControlElement>> controls;
722     return !checkInvalidControlsAndCollectUnhandled(controls);
723 }
724
725 bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<HTMLFormControlElement>>& unhandledInvalidControls)
726 {
727     Ref<HTMLFormElement> protectedThis(*this);
728     // Copy m_associatedElements because event handlers called from
729     // HTMLFormControlElement::checkValidity() might change m_associatedElements.
730     Vector<RefPtr<FormAssociatedElement>> elements;
731     elements.reserveCapacity(m_associatedElements.size());
732     for (auto& associatedElement : m_associatedElements)
733         elements.append(associatedElement);
734     bool hasInvalidControls = false;
735     for (auto& element : elements) {
736         if (element->form() == this && is<HTMLFormControlElement>(*element)) {
737             HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*element);
738             if (!control.checkValidity(&unhandledInvalidControls) && control.form() == this)
739                 hasInvalidControls = true;
740         }
741     }
742     return hasInvalidControls;
743 }
744
745 bool HTMLFormElement::reportValidity()
746 {
747     Ref<HTMLFormElement> protectedThis(*this);
748
749     // Update layout before processing form actions in case the style changes
750     // the Form or button relationships.
751     document().updateLayoutIgnorePendingStylesheets();
752
753     return validateInteractively();
754 }
755
756 #ifndef NDEBUG
757 void HTMLFormElement::assertItemCanBeInPastNamesMap(FormNamedItem* item) const
758 {
759     ASSERT_WITH_SECURITY_IMPLICATION(item);
760     HTMLElement& element = item->asHTMLElement();
761     ASSERT_WITH_SECURITY_IMPLICATION(element.form() == this);
762
763     if (item->isFormAssociatedElement()) {
764         ASSERT_WITH_SECURITY_IMPLICATION(m_associatedElements.find(static_cast<FormAssociatedElement*>(item)) != notFound);
765         return;
766     }
767
768     ASSERT_WITH_SECURITY_IMPLICATION(element.hasTagName(imgTag));
769     ASSERT_WITH_SECURITY_IMPLICATION(m_imageElements.find(&downcast<HTMLImageElement>(element)) != notFound);
770 }
771 #else
772 inline void HTMLFormElement::assertItemCanBeInPastNamesMap(FormNamedItem*) const
773 {
774 }
775 #endif
776
777 RefPtr<HTMLElement> HTMLFormElement::elementFromPastNamesMap(const AtomString& pastName) const
778 {
779     if (pastName.isEmpty() || !m_pastNamesMap)
780         return nullptr;
781     FormNamedItem* item = m_pastNamesMap->get(pastName.impl());
782     if (!item)
783         return nullptr;
784     assertItemCanBeInPastNamesMap(item);
785     return &item->asHTMLElement();
786 }
787
788 void HTMLFormElement::addToPastNamesMap(FormNamedItem* item, const AtomString& pastName)
789 {
790     assertItemCanBeInPastNamesMap(item);
791     if (pastName.isEmpty())
792         return;
793     if (!m_pastNamesMap)
794         m_pastNamesMap = makeUnique<PastNamesMap>();
795     m_pastNamesMap->set(pastName.impl(), item);
796 }
797
798 void HTMLFormElement::removeFromPastNamesMap(FormNamedItem* item)
799 {
800     ASSERT(item);
801     if (!m_pastNamesMap)
802         return;
803
804     for (auto& pastName : m_pastNamesMap->values()) {
805         if (pastName == item)
806             pastName = nullptr; // Keep looping. Single element can have multiple names.
807     }
808 }
809
810 bool HTMLFormElement::matchesValidPseudoClass() const
811 {
812     return m_invalidAssociatedFormControls.computesEmpty();
813 }
814
815 bool HTMLFormElement::matchesInvalidPseudoClass() const
816 {
817     return !matchesValidPseudoClass();
818 }
819
820 // FIXME: Use Ref<HTMLElement> for the function result since there are no non-HTML elements returned here.
821 Vector<Ref<Element>> HTMLFormElement::namedElements(const AtomString& name)
822 {
823     // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
824     Vector<Ref<Element>> namedItems = elements()->namedItems(name);
825
826     auto elementFromPast = elementFromPastNamesMap(name);
827     if (namedItems.size() == 1 && namedItems.first().ptr() != elementFromPast)
828         addToPastNamesMap(downcast<HTMLElement>(namedItems.first().get()).asFormNamedItem(), name);
829     else if (elementFromPast && namedItems.isEmpty())
830         namedItems.append(*elementFromPast);
831
832     return namedItems;
833 }
834
835 void HTMLFormElement::resumeFromDocumentSuspension()
836 {
837     ASSERT(!shouldAutocomplete());
838
839     document().postTask([formElement = makeRef(*this)] (ScriptExecutionContext&) {
840         formElement->resetAssociatedFormControlElements();
841     });
842 }
843
844 void HTMLFormElement::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
845 {
846     if (!shouldAutocomplete()) {
847         oldDocument.unregisterForDocumentSuspensionCallbacks(*this);
848         newDocument.registerForDocumentSuspensionCallbacks(*this);
849     }
850
851     HTMLElement::didMoveToNewDocument(oldDocument, newDocument);
852 }
853
854 bool HTMLFormElement::shouldAutocomplete() const
855 {
856     return !equalLettersIgnoringASCIICase(attributeWithoutSynchronization(autocompleteAttr), "off");
857 }
858
859 void HTMLFormElement::finishParsingChildren()
860 {
861     HTMLElement::finishParsingChildren();
862     document().formController().restoreControlStateIn(*this);
863 }
864
865 const Vector<FormAssociatedElement*>& HTMLFormElement::unsafeAssociatedElements() const
866 {
867     ASSERT(ScriptDisallowedScope::InMainThread::hasDisallowedScope());
868     return m_associatedElements;
869 }
870
871 Vector<Ref<FormAssociatedElement>> HTMLFormElement::copyAssociatedElementsVector() const
872 {
873     return WTF::map(m_associatedElements, [] (auto* rawElement) {
874         return Ref<FormAssociatedElement>(*rawElement);
875     });
876 }
877
878 void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
879 {
880     m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
881     HTMLElement::copyNonAttributePropertiesFromElement(source);
882 }
883
884 HTMLFormElement* HTMLFormElement::findClosestFormAncestor(const Element& startElement)
885 {
886     return const_cast<HTMLFormElement*>(ancestorsOfType<HTMLFormElement>(startElement).first());
887 }
888
889 void HTMLFormElement::setAutocomplete(const AtomString& value)
890 {
891     setAttributeWithoutSynchronization(autocompleteAttr, value);
892 }
893
894 const AtomString& HTMLFormElement::autocomplete() const
895 {
896     static NeverDestroyed<AtomString> on("on", AtomString::ConstructFromLiteral);
897     static NeverDestroyed<AtomString> off("off", AtomString::ConstructFromLiteral);
898
899     return equalIgnoringASCIICase(attributeWithoutSynchronization(autocompleteAttr), "off") ? off : on;
900 }
901
902 } // namespace