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