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