6a4eeb44bd78eece04e52e2d1e1db9bef5c1da71
[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 "Attribute.h"
29 #include "ElementShadow.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 "RenderBox.h"
39 #include "RenderTheme.h"
40 #include "ScriptEventListener.h"
41 #include "ValidationMessage.h"
42 #include "ValidityState.h"
43 #include <wtf/Vector.h>
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48 using namespace std;
49
50 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
51     : LabelableElement(tagName, document)
52     , m_disabled(false)
53     , m_readOnly(false)
54     , m_isRequired(false)
55     , m_valueMatchesRenderer(false)
56     , m_ancestorDisabledState(AncestorDisabledStateUnknown)
57     , m_dataListAncestorState(Unknown)
58     , m_willValidateInitialized(false)
59     , m_willValidate(true)
60     , m_isValid(true)
61     , m_wasChangedSinceLastFormControlChangeEvent(false)
62     , m_hasAutofocused(false)
63 {
64     setForm(form ? form : findFormAncestor());
65     setHasCustomCallbacks();
66 }
67
68 HTMLFormControlElement::~HTMLFormControlElement()
69 {
70 }
71
72 void HTMLFormControlElement::willAddAuthorShadowRoot()
73 {
74     ensureUserAgentShadowRoot();
75 }
76
77 String HTMLFormControlElement::formEnctype() const
78 {
79     return FormSubmission::Attributes::parseEncodingType(fastGetAttribute(formenctypeAttr));
80 }
81
82 void HTMLFormControlElement::setFormEnctype(const String& value)
83 {
84     setAttribute(formenctypeAttr, value);
85 }
86
87 String HTMLFormControlElement::formMethod() const
88 {
89     return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(fastGetAttribute(formmethodAttr)));
90 }
91
92 void HTMLFormControlElement::setFormMethod(const String& value)
93 {
94     setAttribute(formmethodAttr, value);
95 }
96
97 bool HTMLFormControlElement::formNoValidate() const
98 {
99     return fastHasAttribute(formnovalidateAttr);
100 }
101
102 void HTMLFormControlElement::updateAncestorDisabledState() const
103 {
104     HTMLFieldSetElement* fieldSetAncestor = 0;
105     ContainerNode* legendAncestor = 0;
106     for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
107         if (!legendAncestor && ancestor->hasTagName(legendTag))
108             legendAncestor = ancestor;
109         if (ancestor->hasTagName(fieldsetTag)) {
110             fieldSetAncestor = static_cast<HTMLFieldSetElement*>(ancestor);
111             break;
112         }
113     }
114     m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->disabled() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled;
115 }
116
117 void HTMLFormControlElement::ancestorDisabledStateWasChanged()
118 {
119     m_ancestorDisabledState = AncestorDisabledStateUnknown;
120     disabledAttributeChanged();
121 }
122
123 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
124 {
125     if (name == formAttr)
126         formAttributeChanged();
127     else if (name == disabledAttr) {
128         bool oldDisabled = m_disabled;
129         m_disabled = !value.isNull();
130         if (oldDisabled != m_disabled)
131             disabledAttributeChanged();
132     } else if (name == readonlyAttr) {
133         bool oldReadOnly = m_readOnly;
134         m_readOnly = !value.isNull();
135         if (oldReadOnly != m_readOnly) {
136             setNeedsWillValidateCheck();
137             setNeedsStyleRecalc();
138             if (renderer() && renderer()->style()->hasAppearance())
139                 renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
140         }
141     } else if (name == requiredAttr) {
142         bool wasRequired = m_isRequired;
143         m_isRequired = !value.isNull();
144         if (wasRequired != m_isRequired)
145             requiredAttributeChanged();
146     } else
147         HTMLElement::parseAttribute(name, value);
148 }
149
150 void HTMLFormControlElement::disabledAttributeChanged()
151 {
152     setNeedsWillValidateCheck();
153     setNeedsStyleRecalc();
154     invalidateParentDistributionIfNecessary(this, SelectRuleFeatureSet::RuleFeatureDisabled | SelectRuleFeatureSet::RuleFeatureEnabled);
155     if (renderer() && renderer()->style()->hasAppearance())
156         renderer()->theme()->stateChanged(renderer(), EnabledState);
157 }
158
159 void HTMLFormControlElement::requiredAttributeChanged()
160 {
161     setNeedsValidityCheck();
162     // Style recalculation is needed because style selectors may include
163     // :required and :optional pseudo-classes.
164     setNeedsStyleRecalc();
165 }
166
167 static bool shouldAutofocus(HTMLFormControlElement* element)
168 {
169     if (!element->autofocus())
170         return false;
171     if (!element->renderer())
172         return false;
173     if (element->document()->ignoreAutofocus())
174         return false;
175     if (element->document()->isSandboxed(SandboxAutomaticFeatures)) {
176         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
177         element->document()->addConsoleMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, "Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set.");
178         return false;
179     }
180     if (element->hasAutofocused())
181         return false;
182
183     // FIXME: Should this set of hasTagName checks be replaced by a
184     // virtual member function?
185     if (element->hasTagName(inputTag))
186         return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden();
187     if (element->hasTagName(selectTag))
188         return true;
189     if (element->hasTagName(keygenTag))
190         return true;
191     if (element->hasTagName(buttonTag))
192         return true;
193     if (element->hasTagName(textareaTag))
194         return true;
195
196     return false;
197 }
198
199 static void focusPostAttach(Node* element, unsigned)
200
201     static_cast<Element*>(element)->focus(); 
202     element->deref(); 
203 }
204
205 void HTMLFormControlElement::attach()
206 {
207     PostAttachCallbackDisabler disabler(this);
208
209     HTMLElement::attach();
210
211     // The call to updateFromElement() needs to go after the call through
212     // to the base class's attach() because that can sometimes do a close
213     // on the renderer.
214     if (renderer())
215         renderer()->updateFromElement();
216
217     if (shouldAutofocus(this)) {
218         setAutofocused();
219         ref();
220         queuePostAttachCallback(focusPostAttach, this);
221     }
222 }
223
224 void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
225 {
226     FormAssociatedElement::didMoveToNewDocument(oldDocument);
227     HTMLElement::didMoveToNewDocument(oldDocument);
228 }
229
230 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
231 {
232     m_ancestorDisabledState = AncestorDisabledStateUnknown;
233     m_dataListAncestorState = Unknown;
234     setNeedsWillValidateCheck();
235     HTMLElement::insertedInto(insertionPoint);
236     FormAssociatedElement::insertedInto(insertionPoint);
237     return InsertionDone;
238 }
239
240 void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
241 {
242     m_validationMessage = nullptr;
243     m_ancestorDisabledState = AncestorDisabledStateUnknown;
244     m_dataListAncestorState = Unknown;
245     HTMLElement::removedFrom(insertionPoint);
246     FormAssociatedElement::removedFrom(insertionPoint);
247 }
248
249 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
250 {
251     return m_wasChangedSinceLastFormControlChangeEvent;
252 }
253
254 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
255 {
256     m_wasChangedSinceLastFormControlChangeEvent = changed;
257 }
258
259 void HTMLFormControlElement::dispatchFormControlChangeEvent()
260 {
261     HTMLElement::dispatchChangeEvent();
262     setChangedSinceLastFormControlChangeEvent(false);
263 }
264
265 void HTMLFormControlElement::dispatchFormControlInputEvent()
266 {
267     setChangedSinceLastFormControlChangeEvent(true);
268     HTMLElement::dispatchInputEvent();
269 }
270
271 bool HTMLFormControlElement::disabled() const
272 {
273     if (m_disabled)
274         return true;
275
276     if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
277         updateAncestorDisabledState();
278     return m_ancestorDisabledState == AncestorDisabledStateDisabled;
279 }
280
281 bool HTMLFormControlElement::autofocus() const
282 {
283     return hasAttribute(autofocusAttr);
284 }
285
286 bool HTMLFormControlElement::isRequired() const
287 {
288     return m_isRequired;
289 }
290
291 static void updateFromElementCallback(Node* node, unsigned)
292 {
293     ASSERT_ARG(node, node->isElementNode());
294     ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
295     if (RenderObject* renderer = node->renderer())
296         renderer->updateFromElement();
297 }
298
299 void HTMLFormControlElement::didRecalcStyle(StyleChange)
300 {
301     // updateFromElement() can cause the selection to change, and in turn
302     // trigger synchronous layout, so it must not be called during style recalc.
303     if (renderer())
304         queuePostAttachCallback(updateFromElementCallback, this);
305 }
306
307 bool HTMLFormControlElement::supportsFocus() const
308 {
309     return !disabled();
310 }
311
312 bool HTMLFormControlElement::isFocusable() const
313 {
314     // If there's a renderer, make sure the size isn't empty, but if there's no renderer,
315     // it might still be focusable if it's in a canvas subtree (handled in Node::isFocusable).
316     if (renderer() && (!renderer()->isBox() || toRenderBox(renderer())->size().isEmpty()))
317         return false;
318     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
319     // will cover the disabled case.
320     return HTMLElement::isFocusable();
321 }
322
323 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
324 {
325     if (isFocusable())
326         if (document()->frame())
327             return document()->frame()->eventHandler()->tabsToAllFormControls(event);
328     return false;
329 }
330
331 bool HTMLFormControlElement::isMouseFocusable() const
332 {
333 #if PLATFORM(GTK) || PLATFORM(QT)
334     return HTMLElement::isMouseFocusable();
335 #else
336     return false;
337 #endif
338 }
339
340 short HTMLFormControlElement::tabIndex() const
341 {
342     // Skip the supportsFocus check in HTMLElement.
343     return Element::tabIndex();
344 }
345
346 bool HTMLFormControlElement::recalcWillValidate() const
347 {
348     if (m_dataListAncestorState == Unknown) {
349         for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
350             if (ancestor->hasTagName(datalistTag)) {
351                 m_dataListAncestorState = InsideDataList;
352                 break;
353             }
354         }
355         if (m_dataListAncestorState == Unknown)
356             m_dataListAncestorState = NotInsideDataList;
357     }
358     return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
359 }
360
361 bool HTMLFormControlElement::willValidate() const
362 {
363     if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
364         m_willValidateInitialized = true;
365         bool newWillValidate = recalcWillValidate();
366         if (m_willValidate != newWillValidate) {
367             m_willValidate = newWillValidate;
368             const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck();
369         }
370     } else {
371         // If the following assertion fails, setNeedsWillValidateCheck() is not
372         // called correctly when something which changes recalcWillValidate() result
373         // is updated.
374         ASSERT(m_willValidate == recalcWillValidate());
375     }
376     return m_willValidate;
377 }
378
379 void HTMLFormControlElement::setNeedsWillValidateCheck()
380 {
381     // We need to recalculate willValidate immediately because willValidate change can causes style change.
382     bool newWillValidate = recalcWillValidate();
383     if (m_willValidateInitialized && m_willValidate == newWillValidate)
384         return;
385     m_willValidateInitialized = true;
386     m_willValidate = newWillValidate;
387     setNeedsValidityCheck();
388     setNeedsStyleRecalc();
389     if (!m_willValidate)
390         hideVisibleValidationMessage();
391 }
392
393 void HTMLFormControlElement::updateVisibleValidationMessage()
394 {
395     Page* page = document()->page();
396     if (!page)
397         return;
398     String message;
399     if (renderer() && willValidate())
400         message = validationMessage().stripWhiteSpace();
401     if (!m_validationMessage)
402         m_validationMessage = ValidationMessage::create(this);
403     m_validationMessage->updateValidationMessage(message);
404 }
405
406 void HTMLFormControlElement::hideVisibleValidationMessage()
407 {
408     if (m_validationMessage)
409         m_validationMessage->requestToHideMessage();
410 }
411
412 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
413 {
414     if (!willValidate() || isValidFormControlElement())
415         return true;
416     // An event handler can deref this object.
417     RefPtr<HTMLFormControlElement> protector(this);
418     RefPtr<Document> originalDocument(document());
419     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
420     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
421         unhandledInvalidControls->append(this);
422     return false;
423 }
424
425 bool HTMLFormControlElement::isValidFormControlElement()
426 {
427     // If the following assertion fails, setNeedsValidityCheck() is not called
428     // correctly when something which changes validity is updated.
429     ASSERT(m_isValid == validity()->valid());
430     return m_isValid;
431 }
432
433 void HTMLFormControlElement::setNeedsValidityCheck()
434 {
435     bool newIsValid = validity()->valid();
436     if (willValidate() && newIsValid != m_isValid) {
437         // Update style for pseudo classes such as :valid :invalid.
438         setNeedsStyleRecalc();
439     }
440     m_isValid = newIsValid;
441
442     // Updates only if this control already has a validtion message.
443     if (m_validationMessage && m_validationMessage->isVisible()) {
444         // Calls updateVisibleValidationMessage() even if m_isValid is not
445         // changed because a validation message can be chagned.
446         updateVisibleValidationMessage();
447     }
448 }
449
450 void HTMLFormControlElement::setCustomValidity(const String& error)
451 {
452     FormAssociatedElement::setCustomValidity(error);
453     setNeedsValidityCheck();
454 }
455
456 bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const
457 {
458     return m_validationMessage && m_validationMessage->shadowTreeContains(node);
459 }
460
461 void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
462 {
463     HTMLElement::dispatchBlurEvent(newFocusedNode);
464     hideVisibleValidationMessage();
465 }
466
467 HTMLFormElement* HTMLFormControlElement::virtualForm() const
468 {
469     return FormAssociatedElement::form();
470 }
471
472 bool HTMLFormControlElement::isDefaultButtonForForm() const
473 {
474     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
475 }
476
477 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
478 {
479     for (; node; node = node->parentNode()) {
480         if (node->isElementNode() && toElement(node)->isFormControlElement())
481             return static_cast<HTMLFormControlElement*>(node);
482     }
483     return 0;
484 }
485
486 void HTMLFormControlElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
487 {
488     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
489     LabelableElement::reportMemoryUsage(memoryObjectInfo);
490     info.addMember(m_validationMessage);
491 }
492
493 } // namespace Webcore