Replace some auto* with RefPtr within WebCore/html
[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-2017 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     auto& 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     RefPtr<Element> previousAncestor;
124     for (RefPtr<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     invalidateStyleForSubtree();
178     if (renderer() && renderer()->style().hasAppearance())
179         renderer()->theme().stateChanged(*renderer(), ControlStates::EnabledState);
180 }
181
182 void HTMLFormControlElement::readOnlyAttributeChanged()
183 {
184     setNeedsWillValidateCheck();
185     invalidateStyleForSubtree();
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     invalidateStyleForSubtree();
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->isConnected() || !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 = makeRefPtr(document().view());
241         if (frameView && frameView->layoutContext().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, Document& newDocument)
254 {
255     FormAssociatedElement::didMoveToNewDocument(oldDocument);
256     HTMLElement::didMoveToNewDocument(oldDocument, newDocument);
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::InsertedIntoAncestorResult HTMLFormControlElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
278 {
279     m_dataListAncestorState = Unknown;
280     setNeedsWillValidateCheck();
281     if (willValidate() && !isValidFormControlElement())
282         addInvalidElementToAncestorFromInsertionPoint(*this, &parentOfInsertedTree);
283     if (document().hasDisabledFieldsetElement())
284         setAncestorDisabled(computeIsDisabledByFieldsetAncestor());
285     HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
286     FormAssociatedElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
287     return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
288 }
289
290 void HTMLFormControlElement::didFinishInsertingNode()
291 {
292     resetFormOwner();
293 }
294
295 void HTMLFormControlElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
296 {
297     bool wasMatchingInvalidPseudoClass = willValidate() && !isValidFormControlElement();
298
299     m_validationMessage = nullptr;
300     if (m_disabledByAncestorFieldset)
301         setAncestorDisabled(computeIsDisabledByFieldsetAncestor());
302     m_dataListAncestorState = Unknown;
303     HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
304     FormAssociatedElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
305
306     if (wasMatchingInvalidPseudoClass)
307         removeInvalidElementToAncestorFromInsertionPoint(*this, &oldParentOfRemovedTree);
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     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     return isFocusable()
374         && document().frame()
375         && document().frame()->eventHandler().tabsToAllFormControls(event);
376 }
377
378 bool HTMLFormControlElement::isMouseFocusable() const
379 {
380 #if PLATFORM(GTK)
381     return HTMLElement::isMouseFocusable();
382 #else
383     return false;
384 #endif
385 }
386
387 bool HTMLFormControlElement::matchesValidPseudoClass() const
388 {
389     return willValidate() && isValidFormControlElement();
390 }
391
392 bool HTMLFormControlElement::matchesInvalidPseudoClass() const
393 {
394     return willValidate() && !isValidFormControlElement();
395 }
396
397 int HTMLFormControlElement::tabIndex() const
398 {
399     // Skip the supportsFocus check in HTMLElement.
400     return Element::tabIndex();
401 }
402
403 bool HTMLFormControlElement::computeWillValidate() const
404 {
405     if (m_dataListAncestorState == Unknown) {
406         for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
407             if (ancestor->hasTagName(datalistTag)) {
408                 m_dataListAncestorState = InsideDataList;
409                 break;
410             }
411         }
412         if (m_dataListAncestorState == Unknown)
413             m_dataListAncestorState = NotInsideDataList;
414     }
415     return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
416 }
417
418 bool HTMLFormControlElement::willValidate() const
419 {
420     if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
421         m_willValidateInitialized = true;
422         bool newWillValidate = computeWillValidate();
423         if (m_willValidate != newWillValidate)
424             m_willValidate = newWillValidate;
425     } else {
426         // If the following assertion fails, setNeedsWillValidateCheck() is not
427         // called correctly when something which changes computeWillValidate() result
428         // is updated.
429         ASSERT(m_willValidate == computeWillValidate());
430     }
431     return m_willValidate;
432 }
433
434 void HTMLFormControlElement::setNeedsWillValidateCheck()
435 {
436     // We need to recalculate willValidate immediately because willValidate change can causes style change.
437     bool newWillValidate = computeWillValidate();
438     if (m_willValidateInitialized && m_willValidate == newWillValidate)
439         return;
440
441     bool wasValid = m_isValid;
442
443     m_willValidateInitialized = true;
444     m_willValidate = newWillValidate;
445
446     updateValidity();
447     invalidateStyleForSubtree();
448
449     if (!m_willValidate && !wasValid) {
450         removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
451         if (RefPtr<HTMLFormElement> form = this->form())
452             form->removeInvalidAssociatedFormControlIfNeeded(*this);
453     }
454
455     if (!m_willValidate)
456         hideVisibleValidationMessage();
457 }
458
459 void HTMLFormControlElement::updateVisibleValidationMessage()
460 {
461     Page* page = document().page();
462     if (!page)
463         return;
464     String message;
465     if (renderer() && willValidate())
466         message = validationMessage().stripWhiteSpace();
467     if (!m_validationMessage)
468         m_validationMessage = std::make_unique<ValidationMessage>(this);
469     m_validationMessage->updateValidationMessage(message);
470 }
471
472 void HTMLFormControlElement::hideVisibleValidationMessage()
473 {
474     if (m_validationMessage)
475         m_validationMessage->requestToHideMessage();
476 }
477
478 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<HTMLFormControlElement>>* unhandledInvalidControls)
479 {
480     if (!willValidate() || isValidFormControlElement())
481         return true;
482     // An event handler can deref this object.
483     Ref<HTMLFormControlElement> protectedThis(*this);
484     Ref<Document> originalDocument(document());
485     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
486     if (needsDefaultAction && unhandledInvalidControls && isConnected() && originalDocument.ptr() == &document())
487         unhandledInvalidControls->append(this);
488     return false;
489 }
490
491 bool HTMLFormControlElement::isShowingValidationMessage() const
492 {
493     return m_validationMessage && m_validationMessage->isVisible();
494 }
495     
496 bool HTMLFormControlElement::reportValidity()
497 {
498     Vector<RefPtr<HTMLFormControlElement>> elements;
499     if (checkValidity(&elements))
500         return true;
501
502     if (elements.isEmpty())
503         return false;
504
505     // Needs to update layout now because we'd like to call isFocusable(), which
506     // has !renderer()->needsLayout() assertion.
507     document().updateLayoutIgnorePendingStylesheets();
508
509     if (isConnected() && isFocusable()) {
510         focusAndShowValidationMessage();
511         return false;
512     }
513
514     if (document().frame()) {
515         String message = makeString("An invalid form control with name='", name(), "' is not focusable.");
516         document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, message);
517     }
518
519     return false;
520 }
521
522 void HTMLFormControlElement::focusAndShowValidationMessage()
523 {
524     // Calling focus() will scroll the element into view.
525     focus();
526     updateVisibleValidationMessage();
527 }
528
529 inline bool HTMLFormControlElement::isValidFormControlElement() const
530 {
531     // If the following assertion fails, updateValidity() is not called
532     // correctly when something which changes validity is updated.
533     ASSERT(m_isValid == isValid());
534     return m_isValid;
535 }
536
537 void HTMLFormControlElement::willChangeForm()
538 {
539     if (HTMLFormElement* form = this->form())
540         form->removeInvalidAssociatedFormControlIfNeeded(*this);
541     FormAssociatedElement::willChangeForm();
542 }
543
544 void HTMLFormControlElement::didChangeForm()
545 {
546     FormAssociatedElement::didChangeForm();
547     if (RefPtr<HTMLFormElement> form = this->form()) {
548         if (m_willValidateInitialized && m_willValidate && !isValidFormControlElement())
549             form->registerInvalidAssociatedFormControl(*this);
550     }
551 }
552
553 void HTMLFormControlElement::updateValidity()
554 {
555     bool willValidate = this->willValidate();
556     bool wasValid = m_isValid;
557
558     m_isValid = isValid();
559
560     if (willValidate && m_isValid != wasValid) {
561         // Update style for pseudo classes such as :valid :invalid.
562         invalidateStyleForSubtree();
563
564         if (!m_isValid) {
565             addInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
566             if (HTMLFormElement* form = this->form())
567                 form->registerInvalidAssociatedFormControl(*this);
568         } else {
569             removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
570             if (HTMLFormElement* form = this->form())
571                 form->removeInvalidAssociatedFormControlIfNeeded(*this);
572         }
573     }
574
575     // Updates only if this control already has a validtion message.
576     if (m_validationMessage && m_validationMessage->isVisible()) {
577         // Calls updateVisibleValidationMessage() even if m_isValid is not
578         // changed because a validation message can be chagned.
579         updateVisibleValidationMessage();
580     }
581 }
582
583 void HTMLFormControlElement::setCustomValidity(const String& error)
584 {
585     FormAssociatedElement::setCustomValidity(error);
586     updateValidity();
587 }
588
589 bool HTMLFormControlElement::validationMessageShadowTreeContains(const Node& node) const
590 {
591     return m_validationMessage && m_validationMessage->shadowTreeContains(node);
592 }
593
594 void HTMLFormControlElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)
595 {
596     HTMLElement::dispatchBlurEvent(WTFMove(newFocusedElement));
597     hideVisibleValidationMessage();
598 }
599
600 #if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
601
602 // FIXME: We should look to share this code with class HTMLFormElement instead of duplicating the logic.
603
604 bool HTMLFormControlElement::shouldAutocorrect() const
605 {
606     const AtomicString& autocorrectValue = attributeWithoutSynchronization(autocorrectAttr);
607     if (!autocorrectValue.isEmpty())
608         return !equalLettersIgnoringASCIICase(autocorrectValue, "off");
609     if (RefPtr<HTMLFormElement> form = this->form())
610         return form->shouldAutocorrect();
611     return true;
612 }
613
614 AutocapitalizeType HTMLFormControlElement::autocapitalizeType() const
615 {
616     AutocapitalizeType type = HTMLElement::autocapitalizeType();
617     if (type == AutocapitalizeTypeDefault) {
618         if (RefPtr<HTMLFormElement> form = this->form())
619             return form->autocapitalizeType();
620     }
621     return type;
622 }
623
624 #endif
625
626 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
627 {
628     for (; node; node = node->parentNode()) {
629         if (is<HTMLFormControlElement>(*node))
630             return downcast<HTMLFormControlElement>(node);
631     }
632     return nullptr;
633 }
634
635 String HTMLFormControlElement::autocomplete() const
636 {
637     return autofillData().idlExposedValue;
638 }
639
640 void HTMLFormControlElement::setAutocomplete(const String& value)
641 {
642     setAttributeWithoutSynchronization(autocompleteAttr, value);
643 }
644
645 AutofillMantle HTMLFormControlElement::autofillMantle() const
646 {
647     return is<HTMLInputElement>(*this) && downcast<HTMLInputElement>(this)->isInputTypeHidden() ? AutofillMantle::Anchor : AutofillMantle::Expectation;
648 }
649
650 AutofillData HTMLFormControlElement::autofillData() const
651 {
652     // FIXME: We could cache the AutofillData if we we had an efficient way to invalidate the cache when
653     // the autofill mantle changed (due to a type change on an <input> element) or the element's form
654     // owner's autocomplete attribute changed or the form owner itself changed.
655
656     return AutofillData::createFromHTMLFormControlElement(*this);
657 }
658
659 } // namespace Webcore