method/enctype/formMethod/formEnctype properties should be limited to known values.
[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 "Document.h"
30 #include "ElementRareData.h"
31 #include "Event.h"
32 #include "EventHandler.h"
33 #include "EventNames.h"
34 #include "Frame.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLInputElement.h"
37 #include "HTMLNames.h"
38 #include "LabelsNodeList.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
46 namespace WebCore {
47
48 using namespace HTMLNames;
49 using namespace std;
50
51 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
52     : HTMLElement(tagName, document)
53     , FormAssociatedElement(form)
54     , m_disabled(false)
55     , m_readOnly(false)
56     , m_required(false)
57     , m_valueMatchesRenderer(false)
58     , m_willValidateInitialized(false)
59     , m_willValidate(true)
60     , m_isValid(true)
61     , m_wasChangedSinceLastFormControlChangeEvent(false)
62     , m_hasAutofocused(false)
63 {
64     if (!this->form())
65         setForm(findFormAncestor());
66     if (this->form())
67         this->form()->registerFormElement(this);
68
69     setHasCustomWillOrDidRecalcStyle();
70 }
71
72 HTMLFormControlElement::~HTMLFormControlElement()
73 {
74     if (form())
75         form()->removeFormElement(this);
76 }
77
78 void HTMLFormControlElement::detach()
79 {
80     m_validationMessage = nullptr;
81     HTMLElement::detach();
82 }
83
84 String HTMLFormControlElement::formEnctype() const
85 {
86     return FormSubmission::Attributes::parseEncodingType(fastGetAttribute(formenctypeAttr));
87 }
88
89 void HTMLFormControlElement::setFormEnctype(const String& value)
90 {
91     setAttribute(formenctypeAttr, value);
92 }
93
94 String HTMLFormControlElement::formMethod() const
95 {
96     return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(fastGetAttribute(formmethodAttr)));
97 }
98
99 void HTMLFormControlElement::setFormMethod(const String& value)
100 {
101     setAttribute(formmethodAttr, value);
102 }
103
104 bool HTMLFormControlElement::formNoValidate() const
105 {
106     return fastHasAttribute(formnovalidateAttr);
107 }
108
109 void HTMLFormControlElement::parseMappedAttribute(Attribute* attr)
110 {
111     if (attr->name() == formAttr) {
112         formAttributeChanged();
113         if (!form())
114             document()->checkedRadioButtons().addButton(this);
115     } else if (attr->name() == disabledAttr) {
116         bool oldDisabled = m_disabled;
117         m_disabled = !attr->isNull();
118         if (oldDisabled != m_disabled) {
119             setNeedsStyleRecalc();
120             if (renderer() && renderer()->style()->hasAppearance())
121                 renderer()->theme()->stateChanged(renderer(), EnabledState);
122         }
123     } else if (attr->name() == readonlyAttr) {
124         bool oldReadOnly = m_readOnly;
125         m_readOnly = !attr->isNull();
126         if (oldReadOnly != m_readOnly) {
127             setNeedsStyleRecalc();
128             if (renderer() && renderer()->style()->hasAppearance())
129                 renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
130         }
131     } else if (attr->name() == requiredAttr) {
132         bool oldRequired = m_required;
133         m_required = !attr->isNull();
134         if (oldRequired != m_required) {
135             setNeedsValidityCheck();
136             setNeedsStyleRecalc(); // Updates for :required :optional classes.
137         }
138     } else
139         HTMLElement::parseMappedAttribute(attr);
140     setNeedsWillValidateCheck();
141 }
142
143 static bool shouldAutofocus(HTMLFormControlElement* element)
144 {
145     if (!element->autofocus())
146         return false;
147     if (!element->renderer())
148         return false;
149     if (element->document()->ignoreAutofocus())
150         return false;
151     if (element->hasAutofocused())
152         return false;
153
154     // FIXME: Should this set of hasTagName checks be replaced by a
155     // virtual member function?
156     if (element->hasTagName(inputTag))
157         return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden();
158     if (element->hasTagName(selectTag))
159         return true;
160     if (element->hasTagName(keygenTag))
161         return true;
162     if (element->hasTagName(buttonTag))
163         return true;
164     if (element->hasTagName(textareaTag))
165         return true;
166
167     return false;
168 }
169
170 static void focusPostAttach(Node* element, unsigned)
171
172     static_cast<Element*>(element)->focus(); 
173     element->deref(); 
174 }
175
176 void HTMLFormControlElement::attach()
177 {
178     ASSERT(!attached());
179
180     suspendPostAttachCallbacks();
181
182     HTMLElement::attach();
183
184     // The call to updateFromElement() needs to go after the call through
185     // to the base class's attach() because that can sometimes do a close
186     // on the renderer.
187     if (renderer())
188         renderer()->updateFromElement();
189
190     if (shouldAutofocus(this)) {
191         setAutofocused();
192         ref();
193         queuePostAttachCallback(focusPostAttach, this);
194     }
195
196     resumePostAttachCallbacks();
197 }
198
199 void HTMLFormControlElement::willMoveToNewOwnerDocument()
200 {
201     FormAssociatedElement::willMoveToNewOwnerDocument();
202     HTMLElement::willMoveToNewOwnerDocument();
203 }
204
205 void HTMLFormControlElement::insertedIntoTree(bool deep)
206 {
207     FormAssociatedElement::insertedIntoTree();
208     if (!form())
209         document()->checkedRadioButtons().addButton(this);
210
211     HTMLElement::insertedIntoTree(deep);
212 }
213
214 void HTMLFormControlElement::removedFromTree(bool deep)
215 {
216     FormAssociatedElement::removedFromTree();
217     HTMLElement::removedFromTree(deep);
218 }
219
220 void HTMLFormControlElement::insertedIntoDocument()
221 {
222     HTMLElement::insertedIntoDocument();
223     FormAssociatedElement::insertedIntoDocument();
224 }
225
226 void HTMLFormControlElement::removedFromDocument()
227 {
228     HTMLElement::removedFromDocument();
229     FormAssociatedElement::removedFromDocument();
230 }
231
232 const AtomicString& HTMLFormControlElement::formControlName() const
233 {
234     const AtomicString& name = fastGetAttribute(nameAttr);
235     return name.isNull() ? emptyAtom : name;
236 }
237
238 void HTMLFormControlElement::setName(const AtomicString& value)
239 {
240     setAttribute(nameAttr, value);
241 }
242
243 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
244 {
245     return m_wasChangedSinceLastFormControlChangeEvent;
246 }
247
248 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
249 {
250     m_wasChangedSinceLastFormControlChangeEvent = changed;
251 }
252
253 void HTMLFormControlElement::dispatchFormControlChangeEvent()
254 {
255     HTMLElement::dispatchChangeEvent();
256     setChangedSinceLastFormControlChangeEvent(false);
257 }
258
259 void HTMLFormControlElement::dispatchFormControlInputEvent()
260 {
261     setChangedSinceLastFormControlChangeEvent(true);
262     HTMLElement::dispatchInputEvent();
263 }
264
265 void HTMLFormControlElement::setDisabled(bool b)
266 {
267     setAttribute(disabledAttr, b ? "" : 0);
268 }
269
270 bool HTMLFormControlElement::autofocus() const
271 {
272     return hasAttribute(autofocusAttr);
273 }
274
275 bool HTMLFormControlElement::required() const
276 {
277     return m_required;
278 }
279
280 static void updateFromElementCallback(Node* node, unsigned)
281 {
282     ASSERT_ARG(node, node->isElementNode());
283     ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
284     ASSERT(node->renderer());
285     if (RenderObject* renderer = node->renderer())
286         renderer->updateFromElement();
287 }
288
289 void HTMLFormControlElement::didRecalcStyle(StyleChange)
290 {
291     // updateFromElement() can cause the selection to change, and in turn
292     // trigger synchronous layout, so it must not be called during style recalc.
293     if (renderer())
294         queuePostAttachCallback(updateFromElementCallback, this);
295 }
296
297 bool HTMLFormControlElement::supportsFocus() const
298 {
299     return !m_disabled;
300 }
301
302 bool HTMLFormControlElement::isFocusable() const
303 {
304     if (!renderer() || !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())
305         return false;
306     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
307     // will cover the disabled case.
308     return HTMLElement::isFocusable();
309 }
310
311 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
312 {
313     if (isFocusable())
314         if (document()->frame())
315             return document()->frame()->eventHandler()->tabsToAllFormControls(event);
316     return false;
317 }
318
319 bool HTMLFormControlElement::isMouseFocusable() const
320 {
321 #if PLATFORM(GTK) || PLATFORM(QT)
322     return HTMLElement::isMouseFocusable();
323 #else
324     return false;
325 #endif
326 }
327
328 short HTMLFormControlElement::tabIndex() const
329 {
330     // Skip the supportsFocus check in HTMLElement.
331     return Element::tabIndex();
332 }
333
334 bool HTMLFormControlElement::recalcWillValidate() const
335 {
336     // FIXME: Should return false if this element has a datalist element as an
337     // ancestor. See HTML5 4.10.10 'The datalist element.'
338     return !m_disabled && !m_readOnly;
339 }
340
341 bool HTMLFormControlElement::willValidate() const
342 {
343     if (!m_willValidateInitialized) {
344         m_willValidateInitialized = true;
345         m_willValidate = recalcWillValidate();
346     } else {
347         // If the following assertion fails, setNeedsWillValidateCheck() is not
348         // called correctly when something which changes recalcWillValidate() result
349         // is updated.
350         ASSERT(m_willValidate == recalcWillValidate());
351     }
352     return m_willValidate;
353 }
354
355 void HTMLFormControlElement::setNeedsWillValidateCheck()
356 {
357     // We need to recalculate willValidte immediately because willValidate
358     // change can causes style change.
359     bool newWillValidate = recalcWillValidate();
360     if (m_willValidateInitialized && m_willValidate == newWillValidate)
361         return;
362     m_willValidateInitialized = true;
363     m_willValidate = newWillValidate;
364     setNeedsStyleRecalc();
365     if (!m_willValidate)
366         hideVisibleValidationMessage();
367 }
368
369 String HTMLFormControlElement::validationMessage()
370 {
371     return validity()->validationMessage();
372 }
373
374 void HTMLFormControlElement::updateVisibleValidationMessage()
375 {
376     Page* page = document()->page();
377     if (!page)
378         return;
379     String message;
380     if (renderer() && willValidate()) {
381         message = validationMessage().stripWhiteSpace();
382         // HTML5 specification doesn't ask UA to show the title attribute value
383         // with the validationMessage.  However, this behavior is same as Opera
384         // and the specification describes such behavior as an example.
385         const AtomicString& title = getAttribute(titleAttr);
386         if (!message.isEmpty() && !title.isEmpty()) {
387             message.append('\n');
388             message.append(title);
389         }
390     }
391     if (message.isEmpty()) {
392         hideVisibleValidationMessage();
393         return;
394     }
395     if (!m_validationMessage) {
396         m_validationMessage = ValidationMessage::create(this);
397         m_validationMessage->setMessage(message);
398     } else {
399         // Call setMessage() even if m_validationMesage->message() == message
400         // because the existing message might be to be hidden.
401         m_validationMessage->setMessage(message);
402     }
403 }
404
405 void HTMLFormControlElement::hideVisibleValidationMessage()
406 {
407     if (m_validationMessage)
408         m_validationMessage->requestToHideMessage();
409 }
410
411 String HTMLFormControlElement::visibleValidationMessage() const
412 {
413     return m_validationMessage ? m_validationMessage->message() : String();
414 }
415
416 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
417 {
418     if (!willValidate() || isValidFormControlElement())
419         return true;
420     // An event handler can deref this object.
421     RefPtr<HTMLFormControlElement> protector(this);
422     RefPtr<Document> originalDocument(document());
423     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
424     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
425         unhandledInvalidControls->append(this);
426     return false;
427 }
428
429 bool HTMLFormControlElement::isValidFormControlElement()
430 {
431     // If the following assertion fails, setNeedsValidityCheck() is not called
432     // correctly when something which changes validity is updated.
433     ASSERT(m_isValid == validity()->valid());
434     return m_isValid;
435 }
436
437 void HTMLFormControlElement::setNeedsValidityCheck()
438 {
439     bool newIsValid = validity()->valid();
440     if (willValidate() && newIsValid != m_isValid) {
441         // Update style for pseudo classes such as :valid :invalid.
442         setNeedsStyleRecalc();
443     }
444     m_isValid = newIsValid;
445
446     // Updates only if this control already has a validtion message.
447     if (!visibleValidationMessage().isEmpty()) {
448         // Calls updateVisibleValidationMessage() even if m_isValid is not
449         // changed because a validation message can be chagned.
450         updateVisibleValidationMessage();
451     }
452 }
453
454 void HTMLFormControlElement::setCustomValidity(const String& error)
455 {
456     validity()->setCustomErrorMessage(error);
457 }
458
459 void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Node> newFocusedNode)
460 {
461     HTMLElement::dispatchBlurEvent(newFocusedNode);
462     hideVisibleValidationMessage();
463 }
464
465 HTMLFormElement* HTMLFormControlElement::virtualForm() const
466 {
467     return FormAssociatedElement::form();
468 }
469
470 bool HTMLFormControlElement::isDefaultButtonForForm() const
471 {
472     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
473 }
474
475 bool HTMLFormControlElement::isLabelable() const
476 {
477     // FIXME: Add meterTag and outputTag to the list once we support them.
478     return hasTagName(buttonTag) || hasTagName(inputTag) || hasTagName(keygenTag)
479 #if ENABLE(METER_TAG)
480         || hasTagName(meterTag)
481 #endif
482 #if ENABLE(PROGRESS_TAG)
483         || hasTagName(progressTag)
484 #endif
485         || hasTagName(selectTag) || hasTagName(textareaTag);
486 }
487
488 PassRefPtr<NodeList> HTMLFormControlElement::labels()
489 {
490     if (!isLabelable())
491         return 0;
492     if (!document())
493         return 0;
494
495     NodeRareData* data = Node::ensureRareData();
496     if (!data->nodeLists()) {
497         data->setNodeLists(NodeListsNodeData::create());
498         treeScope()->addNodeListCache();
499     }
500
501     if (data->nodeLists()->m_labelsNodeListCache)
502         return data->nodeLists()->m_labelsNodeListCache;
503
504     RefPtr<LabelsNodeList> list = LabelsNodeList::create(this);
505     data->nodeLists()->m_labelsNodeListCache = list.get();
506     return list.release();
507 }
508
509 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
510     : HTMLFormControlElement(tagName, doc, f)
511 {
512     document()->registerFormElementWithState(this);
513 }
514
515 HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
516 {
517     document()->unregisterFormElementWithState(this);
518 }
519
520 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument()
521 {
522     document()->unregisterFormElementWithState(this);
523     HTMLFormControlElement::willMoveToNewOwnerDocument();
524 }
525
526 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument()
527 {
528     document()->registerFormElementWithState(this);
529     HTMLFormControlElement::didMoveToNewOwnerDocument();
530 }
531
532 bool HTMLFormControlElementWithState::shouldAutocomplete() const
533 {
534     if (!form())
535         return true;
536     return form()->shouldAutocomplete();
537 }
538
539 bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const
540 {
541     // We don't save/restore control state in a form with autocomplete=off.
542     return attached() && shouldAutocomplete();
543 }
544
545 void HTMLFormControlElementWithState::finishParsingChildren()
546 {
547     HTMLFormControlElement::finishParsingChildren();
548
549     // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false.
550     // But we need to skip restoring process too because a control in another
551     // form might have the same pair of name and type and saved its state.
552     if (!shouldSaveAndRestoreFormControlState())
553         return;
554
555     Document* doc = document();
556     if (doc->hasStateForNewFormElements()) {
557         String state;
558         if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
559             restoreFormControlState(state);
560     }
561 }
562
563 } // namespace Webcore