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)
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.
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.
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.
26 #include "HTMLFormControlElement.h"
28 #include "Attribute.h"
29 #include "ElementShadow.h"
31 #include "EventHandler.h"
32 #include "EventNames.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>
47 using namespace HTMLNames;
50 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
51 : LabelableElement(tagName, document)
55 , m_valueMatchesRenderer(false)
56 , m_ancestorDisabledState(AncestorDisabledStateUnknown)
57 , m_dataListAncestorState(Unknown)
58 , m_willValidateInitialized(false)
59 , m_willValidate(true)
61 , m_wasChangedSinceLastFormControlChangeEvent(false)
62 , m_hasAutofocused(false)
64 setForm(form ? form : findFormAncestor());
65 setHasCustomCallbacks();
68 HTMLFormControlElement::~HTMLFormControlElement()
72 void HTMLFormControlElement::willAddAuthorShadowRoot()
74 ensureUserAgentShadowRoot();
77 String HTMLFormControlElement::formEnctype() const
79 return FormSubmission::Attributes::parseEncodingType(fastGetAttribute(formenctypeAttr));
82 void HTMLFormControlElement::setFormEnctype(const String& value)
84 setAttribute(formenctypeAttr, value);
87 String HTMLFormControlElement::formMethod() const
89 return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(fastGetAttribute(formmethodAttr)));
92 void HTMLFormControlElement::setFormMethod(const String& value)
94 setAttribute(formmethodAttr, value);
97 bool HTMLFormControlElement::formNoValidate() const
99 return fastHasAttribute(formnovalidateAttr);
102 void HTMLFormControlElement::updateAncestorDisabledState() const
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);
114 m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->disabled() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled;
117 void HTMLFormControlElement::ancestorDisabledStateWasChanged()
119 m_ancestorDisabledState = AncestorDisabledStateUnknown;
120 disabledAttributeChanged();
123 void HTMLFormControlElement::parseAttribute(const Attribute& attribute)
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);
141 } else if (attribute.name() == requiredAttr) {
142 bool oldRequired = m_required;
143 m_required = !attribute.isNull();
144 if (oldRequired != m_required)
145 requiredAttributeChanged();
147 HTMLElement::parseAttribute(attribute);
150 void HTMLFormControlElement::disabledAttributeChanged()
152 setNeedsWillValidateCheck();
153 setNeedsStyleRecalc();
154 invalidateParentDistributionIfNecessary(this, SelectRuleFeatureSet::RuleFeatureDisabled);
155 if (renderer() && renderer()->style()->hasAppearance())
156 renderer()->theme()->stateChanged(renderer(), EnabledState);
159 void HTMLFormControlElement::requiredAttributeChanged()
161 setNeedsValidityCheck();
162 // Style recalculation is needed because style selectors may include
163 // :required and :optional pseudo-classes.
164 setNeedsStyleRecalc();
167 static bool shouldAutofocus(HTMLFormControlElement* element)
169 if (!element->autofocus())
171 if (!element->renderer())
173 if (element->document()->ignoreAutofocus())
175 if (element->document()->isSandboxed(SandboxAutomaticFeatures))
177 if (element->hasAutofocused())
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))
186 if (element->hasTagName(keygenTag))
188 if (element->hasTagName(buttonTag))
190 if (element->hasTagName(textareaTag))
196 static void focusPostAttach(Node* element, unsigned)
198 static_cast<Element*>(element)->focus();
202 void HTMLFormControlElement::attach()
206 suspendPostAttachCallbacks();
208 HTMLElement::attach();
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
214 renderer()->updateFromElement();
216 if (shouldAutofocus(this)) {
219 queuePostAttachCallback(focusPostAttach, this);
222 resumePostAttachCallbacks();
225 void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
227 FormAssociatedElement::didMoveToNewDocument(oldDocument);
228 HTMLElement::didMoveToNewDocument(oldDocument);
231 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
233 m_ancestorDisabledState = AncestorDisabledStateUnknown;
234 m_dataListAncestorState = Unknown;
235 setNeedsWillValidateCheck();
236 HTMLElement::insertedInto(insertionPoint);
237 FormAssociatedElement::insertedInto(insertionPoint);
238 return InsertionDone;
241 void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
243 m_validationMessage = nullptr;
244 m_ancestorDisabledState = AncestorDisabledStateUnknown;
245 m_dataListAncestorState = Unknown;
246 HTMLElement::removedFrom(insertionPoint);
247 FormAssociatedElement::removedFrom(insertionPoint);
250 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
252 return m_wasChangedSinceLastFormControlChangeEvent;
255 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
257 m_wasChangedSinceLastFormControlChangeEvent = changed;
260 void HTMLFormControlElement::dispatchFormControlChangeEvent()
262 HTMLElement::dispatchChangeEvent();
263 setChangedSinceLastFormControlChangeEvent(false);
266 void HTMLFormControlElement::dispatchFormControlInputEvent()
268 setChangedSinceLastFormControlChangeEvent(true);
269 HTMLElement::dispatchInputEvent();
272 bool HTMLFormControlElement::disabled() const
277 if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
278 updateAncestorDisabledState();
279 return m_ancestorDisabledState == AncestorDisabledStateDisabled;
282 void HTMLFormControlElement::setDisabled(bool b)
284 setAttribute(disabledAttr, b ? "" : 0);
287 bool HTMLFormControlElement::autofocus() const
289 return hasAttribute(autofocusAttr);
292 bool HTMLFormControlElement::required() const
297 static void updateFromElementCallback(Node* node, unsigned)
299 ASSERT_ARG(node, node->isElementNode());
300 ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
301 if (RenderObject* renderer = node->renderer())
302 renderer->updateFromElement();
305 void HTMLFormControlElement::didRecalcStyle(StyleChange)
307 // updateFromElement() can cause the selection to change, and in turn
308 // trigger synchronous layout, so it must not be called during style recalc.
310 queuePostAttachCallback(updateFromElementCallback, this);
313 bool HTMLFormControlElement::supportsFocus() const
318 bool HTMLFormControlElement::isFocusable() const
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()))
324 // HTMLElement::isFocusable handles visibility and calls suportsFocus which
325 // will cover the disabled case.
326 return HTMLElement::isFocusable();
329 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
332 if (document()->frame())
333 return document()->frame()->eventHandler()->tabsToAllFormControls(event);
337 bool HTMLFormControlElement::isMouseFocusable() const
339 #if PLATFORM(GTK) || PLATFORM(QT)
340 return HTMLElement::isMouseFocusable();
346 short HTMLFormControlElement::tabIndex() const
348 // Skip the supportsFocus check in HTMLElement.
349 return Element::tabIndex();
352 bool HTMLFormControlElement::recalcWillValidate() const
354 if (m_dataListAncestorState == Unknown) {
355 for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
356 if (ancestor->hasTagName(datalistTag)) {
357 m_dataListAncestorState = InsideDataList;
361 if (m_dataListAncestorState == Unknown)
362 m_dataListAncestorState = NotInsideDataList;
364 return m_dataListAncestorState == NotInsideDataList && !disabled() && !m_readOnly;
367 bool HTMLFormControlElement::willValidate() const
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();
377 // If the following assertion fails, setNeedsWillValidateCheck() is not
378 // called correctly when something which changes recalcWillValidate() result
380 ASSERT(m_willValidate == recalcWillValidate());
382 return m_willValidate;
385 void HTMLFormControlElement::setNeedsWillValidateCheck()
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)
391 m_willValidateInitialized = true;
392 m_willValidate = newWillValidate;
393 setNeedsValidityCheck();
394 setNeedsStyleRecalc();
396 hideVisibleValidationMessage();
399 void HTMLFormControlElement::updateVisibleValidationMessage()
401 Page* page = document()->page();
405 if (renderer() && willValidate())
406 message = validationMessage().stripWhiteSpace();
407 if (!m_validationMessage)
408 m_validationMessage = ValidationMessage::create(this);
409 m_validationMessage->updateValidationMessage(message);
412 void HTMLFormControlElement::hideVisibleValidationMessage()
414 if (m_validationMessage)
415 m_validationMessage->requestToHideMessage();
418 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
420 if (!willValidate() || isValidFormControlElement())
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);
431 bool HTMLFormControlElement::isValidFormControlElement()
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());
439 void HTMLFormControlElement::setNeedsValidityCheck()
441 bool newIsValid = validity()->valid();
442 if (willValidate() && newIsValid != m_isValid) {
443 // Update style for pseudo classes such as :valid :invalid.
444 setNeedsStyleRecalc();
446 m_isValid = newIsValid;
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();
456 void HTMLFormControlElement::setCustomValidity(const String& error)
458 FormAssociatedElement::setCustomValidity(error);
459 setNeedsValidityCheck();
462 bool HTMLFormControlElement::shouldMatchReadOnlySelector() const
467 bool HTMLFormControlElement::shouldMatchReadWriteSelector() const
472 bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const
474 return m_validationMessage && m_validationMessage->shadowTreeContains(node);
477 void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
479 HTMLElement::dispatchBlurEvent(newFocusedNode);
480 hideVisibleValidationMessage();
483 HTMLFormElement* HTMLFormControlElement::virtualForm() const
485 return FormAssociatedElement::form();
488 bool HTMLFormControlElement::isDefaultButtonForForm() const
490 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
493 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
495 for (; node; node = node->parentNode()) {
496 if (node->isElementNode() && toElement(node)->isFormControlElement())
497 return static_cast<HTMLFormControlElement*>(node);
502 void HTMLFormControlElement::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
504 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
505 LabelableElement::reportMemoryUsage(memoryObjectInfo);
506 info.addMember(m_validationMessage);
509 } // namespace Webcore