bb42dfd7f810226f4380754efd19f49d40baa3ba
[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 "CharacterNames.h"
30 #include "Chrome.h"
31 #include "ChromeClient.h"
32 #include "Document.h"
33 #include "DocumentParser.h"
34 #include "ElementRareData.h"
35 #include "Event.h"
36 #include "EventHandler.h"
37 #include "EventNames.h"
38 #include "Frame.h"
39 #include "HTMLFormElement.h"
40 #include "HTMLInputElement.h"
41 #include "HTMLNames.h"
42 #include "LabelsNodeList.h"
43 #include "Page.h"
44 #include "RenderBox.h"
45 #include "RenderTextControl.h"
46 #include "RenderTheme.h"
47 #include "ScriptEventListener.h"
48 #include "ValidationMessage.h"
49 #include "ValidityState.h"
50 #include <limits>
51 #include <wtf/Vector.h>
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56 using namespace std;
57
58 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
59     : HTMLElement(tagName, document)
60     , FormAssociatedElement(form)
61     , m_disabled(false)
62     , m_readOnly(false)
63     , m_required(false)
64     , m_valueMatchesRenderer(false)
65     , m_willValidateInitialized(false)
66     , m_willValidate(true)
67     , m_isValid(true)
68 {
69     if (!this->form())
70         setForm(findFormAncestor());
71     if (this->form())
72         this->form()->registerFormElement(this);
73 }
74
75 HTMLFormControlElement::~HTMLFormControlElement()
76 {
77     if (form())
78         form()->removeFormElement(this);
79 }
80
81 void HTMLFormControlElement::detach()
82 {
83     m_validationMessage = 0;
84     HTMLElement::detach();
85 }
86
87 bool HTMLFormControlElement::formNoValidate() const
88 {
89     return fastHasAttribute(formnovalidateAttr);
90 }
91
92 void HTMLFormControlElement::parseMappedAttribute(Attribute* attr)
93 {
94     if (attr->name() == disabledAttr) {
95         bool oldDisabled = m_disabled;
96         m_disabled = !attr->isNull();
97         if (oldDisabled != m_disabled) {
98             setNeedsStyleRecalc();
99             if (renderer() && renderer()->style()->hasAppearance())
100                 renderer()->theme()->stateChanged(renderer(), EnabledState);
101         }
102     } else if (attr->name() == readonlyAttr) {
103         bool oldReadOnly = m_readOnly;
104         m_readOnly = !attr->isNull();
105         if (oldReadOnly != m_readOnly) {
106             setNeedsStyleRecalc();
107             if (renderer() && renderer()->style()->hasAppearance())
108                 renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
109         }
110     } else if (attr->name() == requiredAttr) {
111         bool oldRequired = m_required;
112         m_required = !attr->isNull();
113         if (oldRequired != m_required) {
114             setNeedsValidityCheck();
115             setNeedsStyleRecalc(); // Updates for :required :optional classes.
116         }
117     } else
118         HTMLElement::parseMappedAttribute(attr);
119     setNeedsWillValidateCheck();
120 }
121
122 void HTMLFormControlElement::attach()
123 {
124     ASSERT(!attached());
125
126     HTMLElement::attach();
127
128     // The call to updateFromElement() needs to go after the call through
129     // to the base class's attach() because that can sometimes do a close
130     // on the renderer.
131     if (renderer())
132         renderer()->updateFromElement();
133         
134     // Focus the element if it should honour its autofocus attribute.
135     // We have to determine if the element is a TextArea/Input/Button/Select,
136     // if input type hidden ignore autofocus. So if disabled or readonly.
137     bool isInputTypeHidden = false;
138     if (hasTagName(inputTag))
139         isInputTypeHidden = static_cast<HTMLInputElement*>(this)->isInputTypeHidden();
140
141     if (autofocus() && renderer() && !document()->ignoreAutofocus() && !isReadOnlyFormControl() &&
142             ((hasTagName(inputTag) && !isInputTypeHidden) || hasTagName(selectTag) ||
143               hasTagName(buttonTag) || hasTagName(textareaTag)))
144          focus();
145 }
146
147 void HTMLFormControlElement::willMoveToNewOwnerDocument()
148 {
149     FormAssociatedElement::willMoveToNewOwnerDocument();
150     HTMLElement::willMoveToNewOwnerDocument();
151 }
152
153 void HTMLFormControlElement::insertedIntoTree(bool deep)
154 {
155     FormAssociatedElement::insertedIntoTree();
156     if (!form())
157         document()->checkedRadioButtons().addButton(this);
158
159     HTMLElement::insertedIntoTree(deep);
160 }
161
162 void HTMLFormControlElement::removedFromTree(bool deep)
163 {
164     FormAssociatedElement::removedFromTree();
165     HTMLElement::removedFromTree(deep);
166 }
167
168 const AtomicString& HTMLFormControlElement::formControlName() const
169 {
170     const AtomicString& name = fastGetAttribute(nameAttr);
171     return name.isNull() ? emptyAtom : name;
172 }
173
174 void HTMLFormControlElement::setName(const AtomicString& value)
175 {
176     setAttribute(nameAttr, value);
177 }
178
179 void HTMLFormControlElement::dispatchFormControlChangeEvent()
180 {
181     HTMLElement::dispatchChangeEvents();
182 }
183
184 void HTMLFormControlElement::dispatchFormControlInputEvent()
185 {
186     HTMLElement::dispatchInputEvents();
187 }
188
189 void HTMLFormControlElement::setDisabled(bool b)
190 {
191     setAttribute(disabledAttr, b ? "" : 0);
192 }
193
194 bool HTMLFormControlElement::autofocus() const
195 {
196     return hasAttribute(autofocusAttr);
197 }
198
199 bool HTMLFormControlElement::required() const
200 {
201     return m_required;
202 }
203
204 static void updateFromElementCallback(Node* node)
205 {
206     ASSERT_ARG(node, node->isElementNode());
207     ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
208     ASSERT(node->renderer());
209     if (RenderObject* renderer = node->renderer())
210         renderer->updateFromElement();
211 }
212
213 void HTMLFormControlElement::recalcStyle(StyleChange change)
214 {
215     HTMLElement::recalcStyle(change);
216
217     // updateFromElement() can cause the selection to change, and in turn
218     // trigger synchronous layout, so it must not be called during style recalc.
219     if (renderer())
220         queuePostAttachCallback(updateFromElementCallback, this);
221 }
222
223 bool HTMLFormControlElement::supportsFocus() const
224 {
225     return !m_disabled;
226 }
227
228 bool HTMLFormControlElement::isFocusable() const
229 {
230     if (!renderer() || 
231         !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())
232         return false;
233     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
234     // will cover the disabled case.
235     return HTMLElement::isFocusable();
236 }
237
238 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
239 {
240     if (isFocusable())
241         if (document()->frame())
242             return document()->frame()->eventHandler()->tabsToAllControls(event);
243     return false;
244 }
245
246 bool HTMLFormControlElement::isMouseFocusable() const
247 {
248 #if PLATFORM(GTK) || PLATFORM(QT)
249     return HTMLElement::isMouseFocusable();
250 #else
251     return false;
252 #endif
253 }
254
255 short HTMLFormControlElement::tabIndex() const
256 {
257     // Skip the supportsFocus check in HTMLElement.
258     return Element::tabIndex();
259 }
260
261 bool HTMLFormControlElement::recalcWillValidate() const
262 {
263     // FIXME: Should return false if this element has a datalist element as an
264     // ancestor. See HTML5 4.10.10 'The datalist element.'
265     return !m_disabled && !m_readOnly;
266 }
267
268 bool HTMLFormControlElement::willValidate() const
269 {
270     if (!m_willValidateInitialized) {
271         m_willValidateInitialized = true;
272         m_willValidate = recalcWillValidate();
273     } else {
274         // If the following assertion fails, setNeedsWillValidateCheck() is not
275         // called correctly when something which changes recalcWillValidate() result
276         // is updated.
277         ASSERT(m_willValidate == recalcWillValidate());
278     }
279     return m_willValidate;
280 }
281
282 void HTMLFormControlElement::setNeedsWillValidateCheck()
283 {
284     // We need to recalculate willValidte immediately because willValidate
285     // change can causes style change.
286     bool newWillValidate = recalcWillValidate();
287     if (m_willValidateInitialized && m_willValidate == newWillValidate)
288         return;
289     m_willValidateInitialized = true;
290     m_willValidate = newWillValidate;
291     setNeedsStyleRecalc();
292     if (!m_willValidate)
293         hideVisibleValidationMessage();
294 }
295
296 String HTMLFormControlElement::validationMessage()
297 {
298     return validity()->validationMessage();
299 }
300
301 void HTMLFormControlElement::updateVisibleValidationMessage()
302 {
303     Page* page = document()->page();
304     if (!page)
305         return;
306     String message;
307     if (renderer() && willValidate()) {
308         message = validationMessage().stripWhiteSpace();
309         // HTML5 specification doesn't ask UA to show the title attribute value
310         // with the validationMessage.  However, this behavior is same as Opera
311         // and the specification describes such behavior as an example.
312         const AtomicString& title = getAttribute(titleAttr);
313         if (!message.isEmpty() && !title.isEmpty()) {
314             message.append('\n');
315             message.append(title);
316         }
317     }
318     if (message.isEmpty()) {
319         hideVisibleValidationMessage();
320         return;
321     }
322     if (!m_validationMessage) {
323         m_validationMessage = ValidationMessage::create(this);
324         m_validationMessage->setMessage(message);
325     } else {
326         // Call setMessage() even if m_validationMesage->message() == message
327         // because the existing message might be to be hidden.
328         m_validationMessage->setMessage(message);
329     }
330 }
331
332 void HTMLFormControlElement::hideVisibleValidationMessage()
333 {
334     if (m_validationMessage)
335         m_validationMessage->requestToHideMessage();
336 }
337
338 String HTMLFormControlElement::visibleValidationMessage() const
339 {
340     return m_validationMessage ? m_validationMessage->message() : String();
341 }
342
343 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
344 {
345     if (!willValidate() || isValidFormControlElement())
346         return true;
347     // An event handler can deref this object.
348     RefPtr<HTMLFormControlElement> protector(this);
349     RefPtr<Document> originalDocument(document());
350     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
351     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
352         unhandledInvalidControls->append(this);
353     return false;
354 }
355
356 bool HTMLFormControlElement::isValidFormControlElement()
357 {
358     // If the following assertion fails, setNeedsValidityCheck() is not called
359     // correctly when something which changes validity is updated.
360     ASSERT(m_isValid == validity()->valid());
361     return m_isValid;
362 }
363
364 void HTMLFormControlElement::setNeedsValidityCheck()
365 {
366     bool newIsValid = validity()->valid();
367     if (willValidate() && newIsValid != m_isValid) {
368         // Update style for pseudo classes such as :valid :invalid.
369         setNeedsStyleRecalc();
370     }
371     m_isValid = newIsValid;
372
373     // Updates only if this control already has a validtion message.
374     if (!visibleValidationMessage().isEmpty()) {
375         // Calls updateVisibleValidationMessage() even if m_isValid is not
376         // changed because a validation message can be chagned.
377         updateVisibleValidationMessage();
378     }
379 }
380
381 void HTMLFormControlElement::setCustomValidity(const String& error)
382 {
383     validity()->setCustomErrorMessage(error);
384 }
385
386 void HTMLFormControlElement::dispatchFocusEvent()
387 {
388     if (document()->page())
389         document()->page()->chrome()->client()->formDidFocus(this);
390
391     HTMLElement::dispatchFocusEvent();
392 }
393
394 void HTMLFormControlElement::dispatchBlurEvent()
395 {
396     if (document()->page())
397         document()->page()->chrome()->client()->formDidBlur(this);
398
399     HTMLElement::dispatchBlurEvent();
400     hideVisibleValidationMessage();
401 }
402
403 HTMLFormElement* HTMLFormControlElement::virtualForm() const
404 {
405     return FormAssociatedElement::form();
406 }
407
408 bool HTMLFormControlElement::isDefaultButtonForForm() const
409 {
410     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
411 }
412
413 void HTMLFormControlElement::attributeChanged(Attribute* attr, bool preserveDecls)
414 {
415     if (attr->name() == formAttr) {
416         formAttributeChanged();
417         if (!form())
418             document()->checkedRadioButtons().addButton(this);
419     } else
420         HTMLElement::attributeChanged(attr, preserveDecls);
421 }
422
423 bool HTMLFormControlElement::isLabelable() const
424 {
425     // FIXME: Add meterTag and outputTag to the list once we support them.
426     return hasTagName(buttonTag) || hasTagName(inputTag) || hasTagName(keygenTag)
427 #if ENABLE(METER_TAG)
428         || hasTagName(meterTag)
429 #endif
430 #if ENABLE(PROGRESS_TAG)
431         || hasTagName(progressTag)
432 #endif
433         || hasTagName(selectTag) || hasTagName(textareaTag);
434 }
435
436 PassRefPtr<NodeList> HTMLFormControlElement::labels()
437 {
438     if (!isLabelable())
439         return 0;
440     if (!document())
441         return 0;
442     
443     NodeRareData* data = Node::ensureRareData();
444     if (!data->nodeLists()) {
445         data->setNodeLists(NodeListsNodeData::create());
446         document()->addNodeListCache();
447     }
448     
449     return LabelsNodeList::create(this);
450 }
451
452 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
453     : HTMLFormControlElement(tagName, doc, f)
454 {
455     document()->registerFormElementWithState(this);
456 }
457
458 HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
459 {
460     document()->unregisterFormElementWithState(this);
461 }
462
463 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument()
464 {
465     document()->unregisterFormElementWithState(this);
466     HTMLFormControlElement::willMoveToNewOwnerDocument();
467 }
468
469 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument()
470 {
471     document()->registerFormElementWithState(this);
472     HTMLFormControlElement::didMoveToNewOwnerDocument();
473 }
474
475 bool HTMLFormControlElementWithState::autoComplete() const
476 {
477     if (!form())
478         return true;
479     return form()->autoComplete();
480 }
481
482 bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const
483 {
484     // We don't save/restore control state in a form with autocomplete=off.
485     return attached() && autoComplete();
486 }
487
488 void HTMLFormControlElementWithState::finishParsingChildren()
489 {
490     HTMLFormControlElement::finishParsingChildren();
491
492     // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false.
493     // But we need to skip restoring process too because a control in another
494     // form might have the same pair of name and type and saved its state.
495     if (!shouldSaveAndRestoreFormControlState())
496         return;
497
498     Document* doc = document();
499     if (doc->hasStateForNewFormElements()) {
500         String state;
501         if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
502             restoreFormControlState(state);
503     }
504 }
505
506 void HTMLFormControlElementWithState::defaultEventHandler(Event* event)
507 {
508     if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
509         toRenderTextControl(renderer())->subtreeHasChanged();
510         return;
511     }
512
513     HTMLFormControlElement::defaultEventHandler(event);
514 }
515
516 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
517     : HTMLFormControlElementWithState(tagName, doc, form)
518 {
519 }
520
521 HTMLTextFormControlElement::~HTMLTextFormControlElement()
522 {
523 }
524
525 void HTMLTextFormControlElement::dispatchFocusEvent()
526 {
527     if (supportsPlaceholder())
528         updatePlaceholderVisibility(false);
529     handleFocusEvent();
530     HTMLFormControlElementWithState::dispatchFocusEvent();
531 }
532
533 void HTMLTextFormControlElement::dispatchBlurEvent()
534 {
535     if (supportsPlaceholder())
536         updatePlaceholderVisibility(false);
537     handleBlurEvent();
538     HTMLFormControlElementWithState::dispatchBlurEvent();
539 }
540
541 String HTMLTextFormControlElement::strippedPlaceholder() const
542 {
543     // According to the HTML5 specification, we need to remove CR and LF from
544     // the attribute value.
545     const AtomicString& attributeValue = getAttribute(placeholderAttr);
546     if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
547         return attributeValue;
548
549     Vector<UChar> stripped;
550     unsigned length = attributeValue.length();
551     stripped.reserveCapacity(length);
552     for (unsigned i = 0; i < length; ++i) {
553         UChar character = attributeValue[i];
554         if (character == newlineCharacter || character == carriageReturn)
555             continue;
556         stripped.append(character);
557     }
558     return String::adopt(stripped);
559 }
560
561 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
562
563 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
564 {
565     const AtomicString& attributeValue = getAttribute(placeholderAttr);
566     return attributeValue.string().find(isNotLineBreak) == notFound;
567 }
568
569 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
570 {
571     return supportsPlaceholder()
572         && isEmptyValue()
573         && document()->focusedNode() != this
574         && !isPlaceholderEmpty();
575 }
576
577 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
578 {
579     if (supportsPlaceholder() && renderer())
580         toRenderTextControl(renderer())->updatePlaceholderVisibility(placeholderShouldBeVisible(), placeholderValueChanged);
581 }
582
583 RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout()
584 {
585     if (!isTextFormControl())
586         return 0;
587     document()->updateLayoutIgnorePendingStylesheets();
588     return toRenderTextControl(renderer());
589 }
590
591 void HTMLTextFormControlElement::setSelectionStart(int start)
592 {
593     setSelectionRange(start, max(start, selectionEnd()));
594 }
595
596 void HTMLTextFormControlElement::setSelectionEnd(int end)
597 {
598     setSelectionRange(min(end, selectionStart()), end);
599 }
600
601 void HTMLTextFormControlElement::select()
602 {
603     setSelectionRange(0, numeric_limits<int>::max());
604 }
605
606 void HTMLTextFormControlElement::setSelectionRange(int start, int end)
607 {
608     WebCore::setSelectionRange(this, start, end);
609 }
610
611 int HTMLTextFormControlElement::selectionStart() const
612 {
613     if (!isTextFormControl())
614         return 0;
615     if (document()->focusedNode() != this && cachedSelectionStart() >= 0)
616         return cachedSelectionStart();
617     if (!renderer())
618         return 0;
619     return toRenderTextControl(renderer())->selectionStart();
620 }
621
622 int HTMLTextFormControlElement::selectionEnd() const
623 {
624     if (!isTextFormControl())
625         return 0;
626     if (document()->focusedNode() != this && cachedSelectionEnd() >= 0)
627         return cachedSelectionEnd();
628     if (!renderer())
629         return 0;
630     return toRenderTextControl(renderer())->selectionEnd();
631 }
632
633 PassRefPtr<Range> HTMLTextFormControlElement::selection() const
634 {
635     if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0)
636         return 0;
637     return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd());
638 }
639
640 void HTMLTextFormControlElement::parseMappedAttribute(Attribute* attr)
641 {
642     if (attr->name() == placeholderAttr)
643         updatePlaceholderVisibility(true);
644     else if (attr->name() == onselectAttr)
645         setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr));
646     else if (attr->name() == onchangeAttr)
647         setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr));
648     else
649         HTMLFormControlElementWithState::parseMappedAttribute(attr);
650 }
651
652 } // namespace Webcore