• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = 0;
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     return LabelsNodeList::create(this);
505 }
506 
HTMLFormControlElementWithState(const QualifiedName & tagName,Document * doc,HTMLFormElement * f)507 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
508     : HTMLFormControlElement(tagName, doc, f)
509 {
510     document()->registerFormElementWithState(this);
511 }
512 
~HTMLFormControlElementWithState()513 HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
514 {
515     document()->unregisterFormElementWithState(this);
516 }
517 
willMoveToNewOwnerDocument()518 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument()
519 {
520     document()->unregisterFormElementWithState(this);
521     HTMLFormControlElement::willMoveToNewOwnerDocument();
522 }
523 
didMoveToNewOwnerDocument()524 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument()
525 {
526     document()->registerFormElementWithState(this);
527     HTMLFormControlElement::didMoveToNewOwnerDocument();
528 }
529 
autoComplete() const530 bool HTMLFormControlElementWithState::autoComplete() const
531 {
532     if (!form())
533         return true;
534     return form()->autoComplete();
535 }
536 
shouldSaveAndRestoreFormControlState() const537 bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const
538 {
539     // We don't save/restore control state in a form with autocomplete=off.
540     return attached() && autoComplete();
541 }
542 
finishParsingChildren()543 void HTMLFormControlElementWithState::finishParsingChildren()
544 {
545     HTMLFormControlElement::finishParsingChildren();
546 
547     // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false.
548     // But we need to skip restoring process too because a control in another
549     // form might have the same pair of name and type and saved its state.
550     if (!shouldSaveAndRestoreFormControlState())
551         return;
552 
553     Document* doc = document();
554     if (doc->hasStateForNewFormElements()) {
555         String state;
556         if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
557             restoreFormControlState(state);
558     }
559 }
560 
defaultEventHandler(Event * event)561 void HTMLFormControlElementWithState::defaultEventHandler(Event* event)
562 {
563     if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
564         toRenderTextControl(renderer())->subtreeHasChanged();
565         return;
566     }
567 
568     HTMLFormControlElement::defaultEventHandler(event);
569 }
570 
HTMLTextFormControlElement(const QualifiedName & tagName,Document * doc,HTMLFormElement * form)571 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
572     : HTMLFormControlElementWithState(tagName, doc, form)
573 {
574 }
575 
~HTMLTextFormControlElement()576 HTMLTextFormControlElement::~HTMLTextFormControlElement()
577 {
578 }
579 
insertedIntoDocument()580 void HTMLTextFormControlElement::insertedIntoDocument()
581 {
582     HTMLFormControlElement::insertedIntoDocument();
583     setTextAsOfLastFormControlChangeEvent(value());
584 }
585 
dispatchFocusEvent()586 void HTMLTextFormControlElement::dispatchFocusEvent()
587 {
588     if (supportsPlaceholder())
589         updatePlaceholderVisibility(false);
590     handleFocusEvent();
591     HTMLFormControlElementWithState::dispatchFocusEvent();
592 }
593 
dispatchBlurEvent()594 void HTMLTextFormControlElement::dispatchBlurEvent()
595 {
596     if (supportsPlaceholder())
597         updatePlaceholderVisibility(false);
598     handleBlurEvent();
599     HTMLFormControlElementWithState::dispatchBlurEvent();
600 }
601 
strippedPlaceholder() const602 String HTMLTextFormControlElement::strippedPlaceholder() const
603 {
604     // According to the HTML5 specification, we need to remove CR and LF from
605     // the attribute value.
606     const AtomicString& attributeValue = getAttribute(placeholderAttr);
607     if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
608         return attributeValue;
609 
610     Vector<UChar> stripped;
611     unsigned length = attributeValue.length();
612     stripped.reserveCapacity(length);
613     for (unsigned i = 0; i < length; ++i) {
614         UChar character = attributeValue[i];
615         if (character == newlineCharacter || character == carriageReturn)
616             continue;
617         stripped.append(character);
618     }
619     return String::adopt(stripped);
620 }
621 
isNotLineBreak(UChar ch)622 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
623 
isPlaceholderEmpty() const624 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
625 {
626     const AtomicString& attributeValue = getAttribute(placeholderAttr);
627     return attributeValue.string().find(isNotLineBreak) == notFound;
628 }
629 
placeholderShouldBeVisible() const630 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
631 {
632     return supportsPlaceholder()
633         && isEmptyValue()
634         && isEmptySuggestedValue()
635         && !isPlaceholderEmpty()
636         && (document()->focusedNode() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused()));
637 }
638 
updatePlaceholderVisibility(bool placeholderValueChanged)639 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
640 {
641     if (supportsPlaceholder() && renderer())
642         toRenderTextControl(renderer())->updatePlaceholderVisibility(placeholderShouldBeVisible(), placeholderValueChanged);
643 }
644 
textRendererAfterUpdateLayout()645 RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout()
646 {
647     if (!isTextFormControl())
648         return 0;
649     document()->updateLayoutIgnorePendingStylesheets();
650     return toRenderTextControl(renderer());
651 }
652 
setSelectionStart(int start)653 void HTMLTextFormControlElement::setSelectionStart(int start)
654 {
655     setSelectionRange(start, max(start, selectionEnd()));
656 }
657 
setSelectionEnd(int end)658 void HTMLTextFormControlElement::setSelectionEnd(int end)
659 {
660     setSelectionRange(min(end, selectionStart()), end);
661 }
662 
select()663 void HTMLTextFormControlElement::select()
664 {
665     setSelectionRange(0, numeric_limits<int>::max());
666 }
667 
dispatchFormControlChangeEvent()668 void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
669 {
670     if (m_textAsOfLastFormControlChangeEvent != value()) {
671         HTMLElement::dispatchChangeEvent();
672         setTextAsOfLastFormControlChangeEvent(value());
673     }
674     setChangedSinceLastFormControlChangeEvent(false);
675 }
676 
setSelectionRange(int start,int end)677 void HTMLTextFormControlElement::setSelectionRange(int start, int end)
678 {
679     WebCore::setSelectionRange(this, start, end);
680 }
681 
selectionStart() const682 int HTMLTextFormControlElement::selectionStart() const
683 {
684     if (!isTextFormControl())
685         return 0;
686     if (document()->focusedNode() != this && cachedSelectionStart() >= 0)
687         return cachedSelectionStart();
688     if (!renderer())
689         return 0;
690     return toRenderTextControl(renderer())->selectionStart();
691 }
692 
selectionEnd() const693 int HTMLTextFormControlElement::selectionEnd() const
694 {
695     if (!isTextFormControl())
696         return 0;
697     if (document()->focusedNode() != this && cachedSelectionEnd() >= 0)
698         return cachedSelectionEnd();
699     if (!renderer())
700         return 0;
701     return toRenderTextControl(renderer())->selectionEnd();
702 }
703 
selection() const704 PassRefPtr<Range> HTMLTextFormControlElement::selection() const
705 {
706     if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0)
707         return 0;
708     return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd());
709 }
710 
parseMappedAttribute(Attribute * attr)711 void HTMLTextFormControlElement::parseMappedAttribute(Attribute* attr)
712 {
713     if (attr->name() == placeholderAttr)
714         updatePlaceholderVisibility(true);
715     else if (attr->name() == onselectAttr)
716         setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr));
717     else if (attr->name() == onchangeAttr)
718         setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr));
719     else
720         HTMLFormControlElementWithState::parseMappedAttribute(attr);
721 }
722 
723 } // namespace Webcore
724