a68e559cc50de7e1bba0ef4f96492b53993fe2ce
[WebKit-https.git] / Source / WebCore / html / HTMLFormControlElement.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, 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 "HTMLFormControlElement.h"
27
28 #include "Autofill.h"
29 #include "ControlStates.h"
30 #include "ElementAncestorIterator.h"
31 #include "Event.h"
32 #include "EventHandler.h"
33 #include "EventNames.h"
34 #include "Frame.h"
35 #include "FrameView.h"
36 #include "HTMLFieldSetElement.h"
37 #include "HTMLFormElement.h"
38 #include "HTMLInputElement.h"
39 #include "HTMLLegendElement.h"
40 #include "HTMLTextAreaElement.h"
41 #include "RenderBox.h"
42 #include "RenderTheme.h"
43 #include "StyleTreeResolver.h"
44 #include "ValidationMessage.h"
45 #include <wtf/Ref.h>
46 #include <wtf/Vector.h>
47
48 namespace WebCore {
49
50 using namespace HTMLNames;
51
52 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
53     : LabelableElement(tagName, document)
54     , FormAssociatedElement(form)
55     , m_disabled(false)
56     , m_isReadOnly(false)
57     , m_isRequired(false)
58     , m_valueMatchesRenderer(false)
59     , m_disabledByAncestorFieldset(false)
60     , m_dataListAncestorState(Unknown)
61     , m_willValidateInitialized(false)
62     , m_willValidate(true)
63     , m_isValid(true)
64     , m_wasChangedSinceLastFormControlChangeEvent(false)
65     , m_hasAutofocused(false)
66 {
67     setHasCustomStyleResolveCallbacks();
68 }
69
70 HTMLFormControlElement::~HTMLFormControlElement()
71 {
72     // The calls willChangeForm() and didChangeForm() are virtual, we want the
73     // form to be reset while this object still exists.
74     setForm(nullptr);
75 }
76
77 String HTMLFormControlElement::formEnctype() const
78 {
79     const AtomicString& formEnctypeAttr = attributeWithoutSynchronization(formenctypeAttr);
80     if (formEnctypeAttr.isNull())
81         return emptyString();
82     return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr);
83 }
84
85 void HTMLFormControlElement::setFormEnctype(const String& value)
86 {
87     setAttributeWithoutSynchronization(formenctypeAttr, value);
88 }
89
90 String HTMLFormControlElement::formMethod() const
91 {
92     const AtomicString& formMethodAttr = attributeWithoutSynchronization(formmethodAttr);
93     if (formMethodAttr.isNull())
94         return emptyString();
95     return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr));
96 }
97
98 void HTMLFormControlElement::setFormMethod(const String& value)
99 {
100     setAttributeWithoutSynchronization(formmethodAttr, value);
101 }
102
103 bool HTMLFormControlElement::formNoValidate() const
104 {
105     return hasAttributeWithoutSynchronization(formnovalidateAttr);
106 }
107
108 String HTMLFormControlElement::formAction() const
109 {
110     const AtomicString& value = attributeWithoutSynchronization(formactionAttr);
111     if (value.isEmpty())
112         return document().url();
113     return getURLAttribute(formactionAttr);
114 }
115
116 void HTMLFormControlElement::setFormAction(const AtomicString& value)
117 {
118     setAttributeWithoutSynchronization(formactionAttr, value);
119 }
120
121 bool HTMLFormControlElement::computeIsDisabledByFieldsetAncestor() const
122 {
123     Element* previousAncestor = nullptr;
124     for (Element* ancestor = parentElement(); ancestor; ancestor = ancestor->parentElement()) {
125         if (is<HTMLFieldSetElement>(*ancestor) && ancestor->hasAttributeWithoutSynchronization(disabledAttr)) {
126             HTMLFieldSetElement& fieldSetAncestor = downcast<HTMLFieldSetElement>(*ancestor);
127             bool isInFirstLegend = is<HTMLLegendElement>(previousAncestor) && previousAncestor == fieldSetAncestor.legend();
128             return !isInFirstLegend;
129         }
130         previousAncestor = ancestor;
131     }
132     return false;
133 }
134
135 void HTMLFormControlElement::setAncestorDisabled(bool isDisabled)
136 {
137     ASSERT(computeIsDisabledByFieldsetAncestor() == isDisabled);
138     bool oldValue = m_disabledByAncestorFieldset;
139     m_disabledByAncestorFieldset = isDisabled;
140     if (oldValue != m_disabledByAncestorFieldset)
141         disabledStateChanged();
142 }
143
144 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
145 {
146     if (name == formAttr)
147         formAttributeChanged();
148     else if (name == disabledAttr) {
149         if (canBeActuallyDisabled()) {
150             bool oldDisabled = m_disabled;
151             m_disabled = !value.isNull();
152             if (oldDisabled != m_disabled)
153                 disabledAttributeChanged();
154         }
155     } else if (name == readonlyAttr) {
156         bool wasReadOnly = m_isReadOnly;
157         m_isReadOnly = !value.isNull();
158         if (wasReadOnly != m_isReadOnly)
159             readOnlyAttributeChanged();
160     } else if (name == requiredAttr) {
161         bool wasRequired = m_isRequired;
162         m_isRequired = !value.isNull();
163         if (wasRequired != m_isRequired)
164             requiredAttributeChanged();
165     } else
166         HTMLElement::parseAttribute(name, value);
167 }
168
169 void HTMLFormControlElement::disabledAttributeChanged()
170 {
171     disabledStateChanged();
172 }
173
174 void HTMLFormControlElement::disabledStateChanged()
175 {
176     setNeedsWillValidateCheck();
177     setNeedsStyleRecalc();
178     if (renderer() && renderer()->style().hasAppearance())
179         renderer()->theme().stateChanged(*renderer(), ControlStates::EnabledState);
180 }
181
182 void HTMLFormControlElement::readOnlyAttributeChanged()
183 {
184     setNeedsWillValidateCheck();
185     setNeedsStyleRecalc();
186 }
187
188 void HTMLFormControlElement::requiredAttributeChanged()
189 {
190     updateValidity();
191     // Style recalculation is needed because style selectors may include
192     // :required and :optional pseudo-classes.
193     setNeedsStyleRecalc();
194 }
195
196 static bool shouldAutofocus(HTMLFormControlElement* element)
197 {
198     if (!element->renderer())
199         return false;
200     if (!element->hasAttributeWithoutSynchronization(autofocusAttr))
201         return false;
202     if (!element->inDocument() || !element->document().renderView())
203         return false;
204     if (element->document().isSandboxed(SandboxAutomaticFeatures)) {
205         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
206         element->document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, ASCIILiteral("Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set."));
207         return false;
208     }
209     if (element->hasAutofocused())
210         return false;
211
212     // FIXME: Should this set of hasTagName checks be replaced by a
213     // virtual member function?
214     if (is<HTMLInputElement>(*element))
215         return !downcast<HTMLInputElement>(*element).isInputTypeHidden();
216     if (element->hasTagName(selectTag))
217         return true;
218     if (element->hasTagName(keygenTag))
219         return true;
220     if (element->hasTagName(buttonTag))
221         return true;
222     if (is<HTMLTextAreaElement>(*element))
223         return true;
224
225     return false;
226 }
227
228 void HTMLFormControlElement::didAttachRenderers()
229 {
230     // The call to updateFromElement() needs to go after the call through
231     // to the base class's attach() because that can sometimes do a close
232     // on the renderer.
233     if (renderer())
234         renderer()->updateFromElement();
235
236     if (shouldAutofocus(this)) {
237         setAutofocused();
238
239         RefPtr<HTMLFormControlElement> element = this;
240         auto* frameView = document().view();
241         if (frameView && frameView->isInLayout()) {
242             frameView->queuePostLayoutCallback([element] {
243                 element->focus();
244             });
245         } else {
246             Style::queuePostResolutionCallback([element] {
247                 element->focus();
248             });
249         }
250     }
251 }
252
253 void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
254 {
255     FormAssociatedElement::didMoveToNewDocument(oldDocument);
256     HTMLElement::didMoveToNewDocument(oldDocument);
257 }
258
259 static void addInvalidElementToAncestorFromInsertionPoint(const HTMLFormControlElement& element, ContainerNode* insertionPoint)
260 {
261     if (!is<Element>(insertionPoint))
262         return;
263
264     for (auto& ancestor : lineageOfType<HTMLFieldSetElement>(downcast<Element>(*insertionPoint)))
265         ancestor.addInvalidDescendant(element);
266 }
267
268 static void removeInvalidElementToAncestorFromInsertionPoint(const HTMLFormControlElement& element, ContainerNode* insertionPoint)
269 {
270     if (!is<Element>(insertionPoint))
271         return;
272
273     for (auto& ancestor : lineageOfType<HTMLFieldSetElement>(downcast<Element>(*insertionPoint)))
274         ancestor.removeInvalidDescendant(element);
275 }
276
277 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode& insertionPoint)
278 {
279     m_dataListAncestorState = Unknown;
280     setNeedsWillValidateCheck();
281     if (willValidate() && !isValidFormControlElement())
282         addInvalidElementToAncestorFromInsertionPoint(*this, &insertionPoint);
283     if (document().hasDisabledFieldsetElement())
284         setAncestorDisabled(computeIsDisabledByFieldsetAncestor());
285     HTMLElement::insertedInto(insertionPoint);
286     FormAssociatedElement::insertedInto(insertionPoint);
287     return InsertionShouldCallFinishedInsertingSubtree;
288 }
289
290 void HTMLFormControlElement::finishedInsertingSubtree()
291 {
292     resetFormOwner();
293 }
294
295 void HTMLFormControlElement::removedFrom(ContainerNode& insertionPoint)
296 {
297     bool wasMatchingInvalidPseudoClass = willValidate() && !isValidFormControlElement();
298
299     m_validationMessage = nullptr;
300     if (m_disabledByAncestorFieldset)
301         setAncestorDisabled(computeIsDisabledByFieldsetAncestor());
302     m_dataListAncestorState = Unknown;
303     HTMLElement::removedFrom(insertionPoint);
304     FormAssociatedElement::removedFrom(insertionPoint);
305
306     if (wasMatchingInvalidPseudoClass)
307         removeInvalidElementToAncestorFromInsertionPoint(*this, &insertionPoint);
308 }
309
310 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
311 {
312     m_wasChangedSinceLastFormControlChangeEvent = changed;
313 }
314
315 void HTMLFormControlElement::dispatchChangeEvent()
316 {
317     dispatchScopedEvent(Event::create(eventNames().changeEvent, true, false));
318 }
319
320 void HTMLFormControlElement::dispatchFormControlChangeEvent()
321 {
322     dispatchChangeEvent();
323     setChangedSinceLastFormControlChangeEvent(false);
324 }
325
326 void HTMLFormControlElement::dispatchFormControlInputEvent()
327 {
328     setChangedSinceLastFormControlChangeEvent(true);
329     HTMLElement::dispatchInputEvent();
330 }
331
332 bool HTMLFormControlElement::isDisabledFormControl() const
333 {
334     return m_disabled || m_disabledByAncestorFieldset;
335 }
336
337 bool HTMLFormControlElement::isRequired() const
338 {
339     return m_isRequired;
340 }
341
342 void HTMLFormControlElement::didRecalcStyle(Style::Change)
343 {
344     // updateFromElement() can cause the selection to change, and in turn
345     // trigger synchronous layout, so it must not be called during style recalc.
346     if (renderer()) {
347         RefPtr<HTMLFormControlElement> element = this;
348         Style::queuePostResolutionCallback([element]{
349             if (auto* renderer = element->renderer())
350                 renderer->updateFromElement();
351         });
352     }
353 }
354
355 bool HTMLFormControlElement::supportsFocus() const
356 {
357     return !isDisabledFormControl();
358 }
359
360 bool HTMLFormControlElement::isFocusable() const
361 {
362     // If there's a renderer, make sure the size isn't empty, but if there's no renderer,
363     // it might still be focusable if it's in a canvas subtree (handled in Node::isFocusable).
364     if (renderer() && (!is<RenderBox>(*renderer()) || downcast<RenderBox>(*renderer()).size().isEmpty()))
365         return false;
366     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
367     // will cover the disabled case.
368     return HTMLElement::isFocusable();
369 }
370
371 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
372 {
373     if (isFocusable())
374         if (document().frame())
375             return document().frame()->eventHandler().tabsToAllFormControls(event);
376     return false;
377 }
378
379 bool HTMLFormControlElement::isMouseFocusable() const
380 {
381 #if PLATFORM(GTK)
382     return HTMLElement::isMouseFocusable();
383 #else
384     return false;
385 #endif
386 }
387
388 bool HTMLFormControlElement::matchesValidPseudoClass() const
389 {
390     return willValidate() && isValidFormControlElement();
391 }
392
393 bool HTMLFormControlElement::matchesInvalidPseudoClass() const
394 {
395     return willValidate() && !isValidFormControlElement();
396 }
397
398 int HTMLFormControlElement::tabIndex() const
399 {
400     // Skip the supportsFocus check in HTMLElement.
401     return Element::tabIndex();
402 }
403
404 bool HTMLFormControlElement::computeWillValidate() const
405 {
406     if (m_dataListAncestorState == Unknown) {
407         for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
408             if (ancestor->hasTagName(datalistTag)) {
409                 m_dataListAncestorState = InsideDataList;
410                 break;
411             }
412         }
413         if (m_dataListAncestorState == Unknown)
414             m_dataListAncestorState = NotInsideDataList;
415     }
416     return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
417 }
418
419 bool HTMLFormControlElement::willValidate() const
420 {
421     if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
422         m_willValidateInitialized = true;
423         bool newWillValidate = computeWillValidate();
424         if (m_willValidate != newWillValidate)
425             m_willValidate = newWillValidate;
426     } else {
427         // If the following assertion fails, setNeedsWillValidateCheck() is not
428         // called correctly when something which changes computeWillValidate() result
429         // is updated.
430         ASSERT(m_willValidate == computeWillValidate());
431     }
432     return m_willValidate;
433 }
434
435 void HTMLFormControlElement::setNeedsWillValidateCheck()
436 {
437     // We need to recalculate willValidate immediately because willValidate change can causes style change.
438     bool newWillValidate = computeWillValidate();
439     if (m_willValidateInitialized && m_willValidate == newWillValidate)
440         return;
441
442     bool wasValid = m_isValid;
443
444     m_willValidateInitialized = true;
445     m_willValidate = newWillValidate;
446
447     updateValidity();
448     setNeedsStyleRecalc();
449
450     if (!m_willValidate && !wasValid) {
451         removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
452         if (HTMLFormElement* form = this->form())
453             form->removeInvalidAssociatedFormControlIfNeeded(*this);
454     }
455
456     if (!m_willValidate)
457         hideVisibleValidationMessage();
458 }
459
460 void HTMLFormControlElement::updateVisibleValidationMessage()
461 {
462     Page* page = document().page();
463     if (!page)
464         return;
465     String message;
466     if (renderer() && willValidate())
467         message = validationMessage().stripWhiteSpace();
468     if (!m_validationMessage)
469         m_validationMessage = std::make_unique<ValidationMessage>(this);
470     m_validationMessage->updateValidationMessage(message);
471 }
472
473 void HTMLFormControlElement::hideVisibleValidationMessage()
474 {
475     if (m_validationMessage)
476         m_validationMessage->requestToHideMessage();
477 }
478
479 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement>>* unhandledInvalidControls)
480 {
481     if (!willValidate() || isValidFormControlElement())
482         return true;
483     // An event handler can deref this object.
484     Ref<HTMLFormControlElement> protectedThis(*this);
485     Ref<Document> originalDocument(document());
486     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
487     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument.ptr() == &document())
488         unhandledInvalidControls->append(this);
489     return false;
490 }
491
492 inline bool HTMLFormControlElement::isValidFormControlElement() const
493 {
494     // If the following assertion fails, updateValidity() is not called
495     // correctly when something which changes validity is updated.
496     ASSERT(m_isValid == valid());
497     return m_isValid;
498 }
499
500 void HTMLFormControlElement::willChangeForm()
501 {
502     if (HTMLFormElement* form = this->form())
503         form->removeInvalidAssociatedFormControlIfNeeded(*this);
504     FormAssociatedElement::willChangeForm();
505 }
506
507 void HTMLFormControlElement::didChangeForm()
508 {
509     FormAssociatedElement::didChangeForm();
510     if (HTMLFormElement* form = this->form()) {
511         if (m_willValidateInitialized && m_willValidate && !isValidFormControlElement())
512             form->registerInvalidAssociatedFormControl(*this);
513     }
514 }
515
516 void HTMLFormControlElement::updateValidity()
517 {
518     bool willValidate = this->willValidate();
519     bool wasValid = m_isValid;
520
521     m_isValid = valid();
522
523     if (willValidate && m_isValid != wasValid) {
524         // Update style for pseudo classes such as :valid :invalid.
525         setNeedsStyleRecalc();
526
527         if (!m_isValid) {
528             addInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
529             if (HTMLFormElement* form = this->form())
530                 form->registerInvalidAssociatedFormControl(*this);
531         } else {
532             removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
533             if (HTMLFormElement* form = this->form())
534                 form->removeInvalidAssociatedFormControlIfNeeded(*this);
535         }
536     }
537
538     // Updates only if this control already has a validtion message.
539     if (m_validationMessage && m_validationMessage->isVisible()) {
540         // Calls updateVisibleValidationMessage() even if m_isValid is not
541         // changed because a validation message can be chagned.
542         updateVisibleValidationMessage();
543     }
544 }
545
546 void HTMLFormControlElement::setCustomValidity(const String& error)
547 {
548     FormAssociatedElement::setCustomValidity(error);
549     updateValidity();
550 }
551
552 bool HTMLFormControlElement::validationMessageShadowTreeContains(const Node& node) const
553 {
554     return m_validationMessage && m_validationMessage->shadowTreeContains(node);
555 }
556
557 void HTMLFormControlElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)
558 {
559     HTMLElement::dispatchBlurEvent(WTFMove(newFocusedElement));
560     hideVisibleValidationMessage();
561 }
562
563 HTMLFormElement* HTMLFormControlElement::virtualForm() const
564 {
565     return FormAssociatedElement::form();
566 }
567
568 #if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
569
570 // FIXME: We should look to share this code with class HTMLFormElement instead of duplicating the logic.
571
572 bool HTMLFormControlElement::autocorrect() const
573 {
574     const AtomicString& autocorrectValue = attributeWithoutSynchronization(autocorrectAttr);
575     if (!autocorrectValue.isEmpty())
576         return !equalLettersIgnoringASCIICase(autocorrectValue, "off");
577     if (HTMLFormElement* form = this->form())
578         return form->autocorrect();
579     return true;
580 }
581
582 void HTMLFormControlElement::setAutocorrect(bool autocorrect)
583 {
584     setAttributeWithoutSynchronization(autocorrectAttr, autocorrect ? AtomicString("on", AtomicString::ConstructFromLiteral) : AtomicString("off", AtomicString::ConstructFromLiteral));
585 }
586
587 WebAutocapitalizeType HTMLFormControlElement::autocapitalizeType() const
588 {
589     WebAutocapitalizeType type = autocapitalizeTypeForAttributeValue(attributeWithoutSynchronization(autocapitalizeAttr));
590     if (type == WebAutocapitalizeTypeDefault) {
591         if (HTMLFormElement* form = this->form())
592             return form->autocapitalizeType();
593     }
594     return type;
595 }
596
597 const AtomicString& HTMLFormControlElement::autocapitalize() const
598 {
599     return stringForAutocapitalizeType(autocapitalizeType());
600 }
601
602 void HTMLFormControlElement::setAutocapitalize(const AtomicString& value)
603 {
604     setAttributeWithoutSynchronization(autocapitalizeAttr, value);
605 }
606
607 #endif
608
609 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
610 {
611     for (; node; node = node->parentNode()) {
612         if (is<HTMLFormControlElement>(*node))
613             return downcast<HTMLFormControlElement>(node);
614     }
615     return nullptr;
616 }
617
618 String HTMLFormControlElement::autocomplete() const
619 {
620     return autofillData().idlExposedValue;
621 }
622
623 void HTMLFormControlElement::setAutocomplete(const String& value)
624 {
625     setAttributeWithoutSynchronization(autocompleteAttr, value);
626 }
627
628 AutofillMantle HTMLFormControlElement::autofillMantle() const
629 {
630     return is<HTMLInputElement>(*this) && downcast<HTMLInputElement>(this)->isInputTypeHidden() ? AutofillMantle::Anchor : AutofillMantle::Expectation;
631 }
632
633 AutofillData HTMLFormControlElement::autofillData() const
634 {
635     // FIXME: We could cache the AutofillData if we we had an efficient way to invalidate the cache when
636     // the autofill mantle changed (due to a type change on an <input> element) or the element's form
637     // owner's autocomplete attribute changed or the form owner itself changed.
638
639     return AutofillData::createFromHTMLFormControlElement(*this);
640 }
641
642 } // namespace Webcore