Chaging pseudoClass (:enabled) should cause distribution
[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 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 Attribute& attribute)
124 {
125     if (attribute.name() == formAttr)
126         formAttributeChanged();
127     else if (attribute.name() == disabledAttr) {
128         bool oldDisabled = m_disabled;
129         m_disabled = !attribute.isNull();
130         if (oldDisabled != m_disabled)
131             disabledAttributeChanged();
132     } else if (attribute.name() == readonlyAttr) {
133         bool oldReadOnly = m_readOnly;
134         m_readOnly = !attribute.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 (attribute.name() == requiredAttr) {
142         bool oldRequired = m_required;
143         m_required = !attribute.isNull();
144         if (oldRequired != m_required)
145             requiredAttributeChanged();
146     } else
147         HTMLElement::parseAttribute(attribute);
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         return false;
177     if (element->hasAutofocused())
178         return false;
179
180     // FIXME: Should this set of hasTagName checks be replaced by a
181     // virtual member function?
182     if (element->hasTagName(inputTag))
183         return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden();
184     if (element->hasTagName(selectTag))
185         return true;
186     if (element->hasTagName(keygenTag))
187         return true;
188     if (element->hasTagName(buttonTag))
189         return true;
190     if (element->hasTagName(textareaTag))
191         return true;
192
193     return false;
194 }
195
196 static void focusPostAttach(Node* element, unsigned)
197
198     static_cast<Element*>(element)->focus(); 
199     element->deref(); 
200 }
201
202 void HTMLFormControlElement::attach()
203 {
204     ASSERT(!attached());
205
206     suspendPostAttachCallbacks();
207
208     HTMLElement::attach();
209
210     // The call to updateFromElement() needs to go after the call through
211     // to the base class's attach() because that can sometimes do a close
212     // on the renderer.
213     if (renderer())
214         renderer()->updateFromElement();
215
216     if (shouldAutofocus(this)) {
217         setAutofocused();
218         ref();
219         queuePostAttachCallback(focusPostAttach, this);
220     }
221
222     resumePostAttachCallbacks();
223 }
224
225 void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
226 {
227     FormAssociatedElement::didMoveToNewDocument(oldDocument);
228     HTMLElement::didMoveToNewDocument(oldDocument);
229 }
230
231 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
232 {
233     m_ancestorDisabledState = AncestorDisabledStateUnknown;
234     m_dataListAncestorState = Unknown;
235     setNeedsWillValidateCheck();
236     HTMLElement::insertedInto(insertionPoint);
237     FormAssociatedElement::insertedInto(insertionPoint);
238     return InsertionDone;
239 }
240
241 void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
242 {
243     m_validationMessage = nullptr;
244     m_ancestorDisabledState = AncestorDisabledStateUnknown;
245     m_dataListAncestorState = Unknown;
246     HTMLElement::removedFrom(insertionPoint);
247     FormAssociatedElement::removedFrom(insertionPoint);
248 }
249
250 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
251 {
252     return m_wasChangedSinceLastFormControlChangeEvent;
253 }
254
255 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
256 {
257     m_wasChangedSinceLastFormControlChangeEvent = changed;
258 }
259
260 void HTMLFormControlElement::dispatchFormControlChangeEvent()
261 {
262     HTMLElement::dispatchChangeEvent();
263     setChangedSinceLastFormControlChangeEvent(false);
264 }
265
266 void HTMLFormControlElement::dispatchFormControlInputEvent()
267 {
268     setChangedSinceLastFormControlChangeEvent(true);
269     HTMLElement::dispatchInputEvent();
270 }
271
272 bool HTMLFormControlElement::disabled() const
273 {
274     if (m_disabled)
275         return true;
276
277     if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
278         updateAncestorDisabledState();
279     return m_ancestorDisabledState == AncestorDisabledStateDisabled;
280 }
281
282 void HTMLFormControlElement::setDisabled(bool b)
283 {
284     setAttribute(disabledAttr, b ? "" : 0);
285 }
286
287 bool HTMLFormControlElement::autofocus() const
288 {
289     return hasAttribute(autofocusAttr);
290 }
291
292 bool HTMLFormControlElement::required() const
293 {
294     return m_required;
295 }
296
297 static void updateFromElementCallback(Node* node, unsigned)
298 {
299     ASSERT_ARG(node, node->isElementNode());
300     ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
301     if (RenderObject* renderer = node->renderer())
302         renderer->updateFromElement();
303 }
304
305 void HTMLFormControlElement::didRecalcStyle(StyleChange)
306 {
307     // updateFromElement() can cause the selection to change, and in turn
308     // trigger synchronous layout, so it must not be called during style recalc.
309     if (renderer())
310         queuePostAttachCallback(updateFromElementCallback, this);
311 }
312
313 bool HTMLFormControlElement::supportsFocus() const
314 {
315     return !disabled();
316 }
317
318 bool HTMLFormControlElement::isFocusable() const
319 {
320     // If there's a renderer, make sure the size isn't empty, but if there's no renderer,
321     // it might still be focusable if it's in a canvas subtree (handled in Node::isFocusable).
322     if (renderer() && (!renderer()->isBox() || toRenderBox(renderer())->size().isEmpty()))
323         return false;
324     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
325     // will cover the disabled case.
326     return HTMLElement::isFocusable();
327 }
328
329 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
330 {
331     if (isFocusable())
332         if (document()->frame())
333             return document()->frame()->eventHandler()->tabsToAllFormControls(event);
334     return false;
335 }
336
337 bool HTMLFormControlElement::isMouseFocusable() const
338 {
339 #if PLATFORM(GTK) || PLATFORM(QT)
340     return HTMLElement::isMouseFocusable();
341 #else
342     return false;
343 #endif
344 }
345
346 short HTMLFormControlElement::tabIndex() const
347 {
348     // Skip the supportsFocus check in HTMLElement.
349     return Element::tabIndex();
350 }
351
352 bool HTMLFormControlElement::recalcWillValidate() const
353 {
354     if (m_dataListAncestorState == Unknown) {
355         for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
356             if (ancestor->hasTagName(datalistTag)) {
357                 m_dataListAncestorState = InsideDataList;
358                 break;
359             }
360         }
361         if (m_dataListAncestorState == Unknown)
362             m_dataListAncestorState = NotInsideDataList;
363     }
364     return m_dataListAncestorState == NotInsideDataList && !disabled() && !m_readOnly;
365 }
366
367 bool HTMLFormControlElement::willValidate() const
368 {
369     if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
370         m_willValidateInitialized = true;
371         bool newWillValidate = recalcWillValidate();
372         if (m_willValidate != newWillValidate) {
373             m_willValidate = newWillValidate;
374             const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck();
375         }
376     } else {
377         // If the following assertion fails, setNeedsWillValidateCheck() is not
378         // called correctly when something which changes recalcWillValidate() result
379         // is updated.
380         ASSERT(m_willValidate == recalcWillValidate());
381     }
382     return m_willValidate;
383 }
384
385 void HTMLFormControlElement::setNeedsWillValidateCheck()
386 {
387     // We need to recalculate willValidate immediately because willValidate change can causes style change.
388     bool newWillValidate = recalcWillValidate();
389     if (m_willValidateInitialized && m_willValidate == newWillValidate)
390         return;
391     m_willValidateInitialized = true;
392     m_willValidate = newWillValidate;
393     setNeedsValidityCheck();
394     setNeedsStyleRecalc();
395     if (!m_willValidate)
396         hideVisibleValidationMessage();
397 }
398
399 void HTMLFormControlElement::updateVisibleValidationMessage()
400 {
401     Page* page = document()->page();
402     if (!page)
403         return;
404     String message;
405     if (renderer() && willValidate())
406         message = validationMessage().stripWhiteSpace();
407     if (!m_validationMessage)
408         m_validationMessage = ValidationMessage::create(this);
409     m_validationMessage->updateValidationMessage(message);
410 }
411
412 void HTMLFormControlElement::hideVisibleValidationMessage()
413 {
414     if (m_validationMessage)
415         m_validationMessage->requestToHideMessage();
416 }
417
418 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
419 {
420     if (!willValidate() || isValidFormControlElement())
421         return true;
422     // An event handler can deref this object.
423     RefPtr<HTMLFormControlElement> protector(this);
424     RefPtr<Document> originalDocument(document());
425     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
426     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
427         unhandledInvalidControls->append(this);
428     return false;
429 }
430
431 bool HTMLFormControlElement::isValidFormControlElement()
432 {
433     // If the following assertion fails, setNeedsValidityCheck() is not called
434     // correctly when something which changes validity is updated.
435     ASSERT(m_isValid == validity()->valid());
436     return m_isValid;
437 }
438
439 void HTMLFormControlElement::setNeedsValidityCheck()
440 {
441     bool newIsValid = validity()->valid();
442     if (willValidate() && newIsValid != m_isValid) {
443         // Update style for pseudo classes such as :valid :invalid.
444         setNeedsStyleRecalc();
445     }
446     m_isValid = newIsValid;
447
448     // Updates only if this control already has a validtion message.
449     if (m_validationMessage && m_validationMessage->isVisible()) {
450         // Calls updateVisibleValidationMessage() even if m_isValid is not
451         // changed because a validation message can be chagned.
452         updateVisibleValidationMessage();
453     }
454 }
455
456 void HTMLFormControlElement::setCustomValidity(const String& error)
457 {
458     FormAssociatedElement::setCustomValidity(error);
459     setNeedsValidityCheck();
460 }
461
462 bool HTMLFormControlElement::shouldMatchReadOnlySelector() const
463 {
464     return readOnly();
465 }
466
467 bool HTMLFormControlElement::shouldMatchReadWriteSelector() const
468 {
469     return !readOnly();
470 }
471
472 bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const
473 {
474     return m_validationMessage && m_validationMessage->shadowTreeContains(node);
475 }
476
477 void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
478 {
479     HTMLElement::dispatchBlurEvent(newFocusedNode);
480     hideVisibleValidationMessage();
481 }
482
483 HTMLFormElement* HTMLFormControlElement::virtualForm() const
484 {
485     return FormAssociatedElement::form();
486 }
487
488 bool HTMLFormControlElement::isDefaultButtonForForm() const
489 {
490     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
491 }
492
493 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
494 {
495     for (; node; node = node->parentNode()) {
496         if (node->isElementNode() && toElement(node)->isFormControlElement())
497             return static_cast<HTMLFormControlElement*>(node);
498     }
499     return 0;
500 }
501
502 void HTMLFormControlElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
503 {
504     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
505     LabelableElement::reportMemoryUsage(memoryObjectInfo);
506     info.addMember(m_validationMessage);
507 }
508
509 } // namespace Webcore