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