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