Change Element::isReadOnlyFormControl to Element::shouldMatchReadOnlySelector/shouldM...
[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     if (renderer() && renderer()->style()->hasAppearance())
155         renderer()->theme()->stateChanged(renderer(), EnabledState);
156 }
157
158 void HTMLFormControlElement::requiredAttributeChanged()
159 {
160     setNeedsValidityCheck();
161     // Style recalculation is needed because style selectors may include
162     // :required and :optional pseudo-classes.
163     setNeedsStyleRecalc();
164 }
165
166 static bool shouldAutofocus(HTMLFormControlElement* element)
167 {
168     if (!element->autofocus())
169         return false;
170     if (!element->renderer())
171         return false;
172     if (element->document()->ignoreAutofocus())
173         return false;
174     if (element->document()->isSandboxed(SandboxAutomaticFeatures))
175         return false;
176     if (element->hasAutofocused())
177         return false;
178
179     // FIXME: Should this set of hasTagName checks be replaced by a
180     // virtual member function?
181     if (element->hasTagName(inputTag))
182         return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden();
183     if (element->hasTagName(selectTag))
184         return true;
185     if (element->hasTagName(keygenTag))
186         return true;
187     if (element->hasTagName(buttonTag))
188         return true;
189     if (element->hasTagName(textareaTag))
190         return true;
191
192     return false;
193 }
194
195 static void focusPostAttach(Node* element, unsigned)
196
197     static_cast<Element*>(element)->focus(); 
198     element->deref(); 
199 }
200
201 void HTMLFormControlElement::attach()
202 {
203     ASSERT(!attached());
204
205     suspendPostAttachCallbacks();
206
207     HTMLElement::attach();
208
209     // The call to updateFromElement() needs to go after the call through
210     // to the base class's attach() because that can sometimes do a close
211     // on the renderer.
212     if (renderer())
213         renderer()->updateFromElement();
214
215     if (shouldAutofocus(this)) {
216         setAutofocused();
217         ref();
218         queuePostAttachCallback(focusPostAttach, this);
219     }
220
221     resumePostAttachCallbacks();
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 void HTMLFormControlElement::setDisabled(bool b)
282 {
283     setAttribute(disabledAttr, b ? "" : 0);
284 }
285
286 bool HTMLFormControlElement::autofocus() const
287 {
288     return hasAttribute(autofocusAttr);
289 }
290
291 bool HTMLFormControlElement::required() const
292 {
293     return m_required;
294 }
295
296 static void updateFromElementCallback(Node* node, unsigned)
297 {
298     ASSERT_ARG(node, node->isElementNode());
299     ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
300     ASSERT(node->renderer());
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         // HTML5 specification doesn't ask UA to show the title attribute value
408         // with the validationMessage.  However, this behavior is same as Opera
409         // and the specification describes such behavior as an example.
410         const AtomicString& title = getAttribute(titleAttr);
411         if (!message.isEmpty() && !title.isEmpty()) {
412             message.append('\n');
413             message.append(title);
414         }
415     }
416     if (message.isEmpty()) {
417         hideVisibleValidationMessage();
418         return;
419     }
420     if (!m_validationMessage) {
421         m_validationMessage = ValidationMessage::create(this);
422         m_validationMessage->setMessage(message);
423     } else {
424         // Call setMessage() even if m_validationMesage->message() == message
425         // because the existing message might be to be hidden.
426         m_validationMessage->setMessage(message);
427     }
428 }
429
430 void HTMLFormControlElement::hideVisibleValidationMessage()
431 {
432     if (m_validationMessage)
433         m_validationMessage->requestToHideMessage();
434 }
435
436 String HTMLFormControlElement::visibleValidationMessage() const
437 {
438     return m_validationMessage ? m_validationMessage->message() : String();
439 }
440
441 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
442 {
443     if (!willValidate() || isValidFormControlElement())
444         return true;
445     // An event handler can deref this object.
446     RefPtr<HTMLFormControlElement> protector(this);
447     RefPtr<Document> originalDocument(document());
448     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
449     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
450         unhandledInvalidControls->append(this);
451     return false;
452 }
453
454 bool HTMLFormControlElement::isValidFormControlElement()
455 {
456     // If the following assertion fails, setNeedsValidityCheck() is not called
457     // correctly when something which changes validity is updated.
458     ASSERT(m_isValid == validity()->valid());
459     return m_isValid;
460 }
461
462 void HTMLFormControlElement::setNeedsValidityCheck()
463 {
464     bool newIsValid = validity()->valid();
465     if (willValidate() && newIsValid != m_isValid) {
466         // Update style for pseudo classes such as :valid :invalid.
467         setNeedsStyleRecalc();
468     }
469     m_isValid = newIsValid;
470
471     // Updates only if this control already has a validtion message.
472     if (!visibleValidationMessage().isEmpty()) {
473         // Calls updateVisibleValidationMessage() even if m_isValid is not
474         // changed because a validation message can be chagned.
475         updateVisibleValidationMessage();
476     }
477 }
478
479 void HTMLFormControlElement::setCustomValidity(const String& error)
480 {
481     FormAssociatedElement::setCustomValidity(error);
482     setNeedsValidityCheck();
483 }
484
485 bool HTMLFormControlElement::shouldMatchReadOnlySelector() const
486 {
487     return readOnly();
488 }
489
490 bool HTMLFormControlElement::shouldMatchReadWriteSelector() const
491 {
492     return !readOnly();
493 }
494
495 bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const
496 {
497     return m_validationMessage && m_validationMessage->shadowTreeContains(node);
498 }
499
500 void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
501 {
502     HTMLElement::dispatchBlurEvent(newFocusedNode);
503     hideVisibleValidationMessage();
504 }
505
506 HTMLFormElement* HTMLFormControlElement::virtualForm() const
507 {
508     return FormAssociatedElement::form();
509 }
510
511 bool HTMLFormControlElement::isDefaultButtonForForm() const
512 {
513     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
514 }
515
516 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
517 {
518     for (; node; node = node->parentNode()) {
519         if (node->isElementNode() && toElement(node)->isFormControlElement())
520             return static_cast<HTMLFormControlElement*>(node);
521     }
522     return 0;
523 }
524
525 } // namespace Webcore