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