WebCore/html/HTMLFormControlElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "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 "LegacyHTMLTreeBuilder.h"
       
    42 #include "LegacyHTMLDocumentParser.h"
       
    43 #include "LabelsNodeList.h"
       
    44 #include "Page.h"
       
    45 #include "RenderBox.h"
       
    46 #include "RenderTextControl.h"
       
    47 #include "RenderTheme.h"
       
    48 #include "ScriptEventListener.h"
       
    49 #include "ValidityState.h"
       
    50 #include <wtf/Vector.h>
       
    51 
       
    52 namespace WebCore {
       
    53 
       
    54 using namespace HTMLNames;
       
    55 
       
    56 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
       
    57     : HTMLElement(tagName, document)
       
    58     , m_form(form)
       
    59     , m_disabled(false)
       
    60     , m_readOnly(false)
       
    61     , m_required(false)
       
    62     , m_valueMatchesRenderer(false)
       
    63     , m_willValidateInitialized(false)
       
    64     , m_willValidate(true)
       
    65     , m_isValid(true)
       
    66 {
       
    67     if (!m_form)
       
    68         m_form = findFormAncestor();
       
    69     if (m_form)
       
    70         m_form->registerFormElement(this);
       
    71 }
       
    72 
       
    73 HTMLFormControlElement::~HTMLFormControlElement()
       
    74 {
       
    75     if (m_form)
       
    76         m_form->removeFormElement(this);
       
    77 }
       
    78 
       
    79 bool HTMLFormControlElement::formNoValidate() const
       
    80 {
       
    81     return !getAttribute(formnovalidateAttr).isNull();
       
    82 }
       
    83 
       
    84 ValidityState* HTMLFormControlElement::validity()
       
    85 {
       
    86     if (!m_validityState)
       
    87         m_validityState = ValidityState::create(this);
       
    88 
       
    89     return m_validityState.get();
       
    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::insertedIntoTree(bool deep)
       
   148 {
       
   149     if (!m_form) {
       
   150         // This handles the case of a new form element being created by
       
   151         // JavaScript and inserted inside a form.  In the case of the parser
       
   152         // setting a form, we will already have a non-null value for m_form, 
       
   153         // and so we don't need to do anything.
       
   154         m_form = findFormAncestor();
       
   155         if (m_form)
       
   156             m_form->registerFormElement(this);
       
   157         else
       
   158             document()->checkedRadioButtons().addButton(this);
       
   159     }
       
   160 
       
   161     HTMLElement::insertedIntoTree(deep);
       
   162 }
       
   163 
       
   164 static inline Node* findRoot(Node* n)
       
   165 {
       
   166     Node* root = n;
       
   167     for (; n; n = n->parentNode())
       
   168         root = n;
       
   169     return root;
       
   170 }
       
   171 
       
   172 void HTMLFormControlElement::removedFromTree(bool deep)
       
   173 {
       
   174     // If the form and element are both in the same tree, preserve the connection to the form.
       
   175     // Otherwise, null out our form and remove ourselves from the form's list of elements.
       
   176     LegacyHTMLTreeBuilder* treeBuilder = 0;
       
   177     if (DocumentParser* parser = document()->parser())
       
   178         treeBuilder = parser->htmlTreeBuilder();
       
   179 
       
   180     if (m_form && !(treeBuilder && treeBuilder->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) {
       
   181         m_form->removeFormElement(this);
       
   182         m_form = 0;
       
   183     }
       
   184 
       
   185     HTMLElement::removedFromTree(deep);
       
   186 }
       
   187 
       
   188 const AtomicString& HTMLFormControlElement::formControlName() const
       
   189 {
       
   190     const AtomicString& name = fastGetAttribute(nameAttr);
       
   191     return name.isNull() ? emptyAtom : name;
       
   192 }
       
   193 
       
   194 void HTMLFormControlElement::setName(const AtomicString& value)
       
   195 {
       
   196     setAttribute(nameAttr, value);
       
   197 }
       
   198 
       
   199 void HTMLFormControlElement::dispatchFormControlChangeEvent()
       
   200 {
       
   201     dispatchEvent(Event::create(eventNames().changeEvent, true, false));
       
   202 }
       
   203 
       
   204 void HTMLFormControlElement::setDisabled(bool b)
       
   205 {
       
   206     setAttribute(disabledAttr, b ? "" : 0);
       
   207 }
       
   208 
       
   209 bool HTMLFormControlElement::autofocus() const
       
   210 {
       
   211     return hasAttribute(autofocusAttr);
       
   212 }
       
   213 
       
   214 bool HTMLFormControlElement::required() const
       
   215 {
       
   216     return m_required;
       
   217 }
       
   218 
       
   219 static void updateFromElementCallback(Node* node)
       
   220 {
       
   221     ASSERT_ARG(node, node->isElementNode());
       
   222     ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
       
   223     ASSERT(node->renderer());
       
   224     if (RenderObject* renderer = node->renderer())
       
   225         renderer->updateFromElement();
       
   226 }
       
   227 
       
   228 void HTMLFormControlElement::recalcStyle(StyleChange change)
       
   229 {
       
   230     HTMLElement::recalcStyle(change);
       
   231 
       
   232     // updateFromElement() can cause the selection to change, and in turn
       
   233     // trigger synchronous layout, so it must not be called during style recalc.
       
   234     if (renderer())
       
   235         queuePostAttachCallback(updateFromElementCallback, this);
       
   236 }
       
   237 
       
   238 bool HTMLFormControlElement::supportsFocus() const
       
   239 {
       
   240     return !disabled();
       
   241 }
       
   242 
       
   243 bool HTMLFormControlElement::isFocusable() const
       
   244 {
       
   245     if (!renderer() || 
       
   246         !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())
       
   247         return false;
       
   248     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
       
   249     // will cover the disabled case.
       
   250     return HTMLElement::isFocusable();
       
   251 }
       
   252 
       
   253 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
       
   254 {
       
   255     if (isFocusable())
       
   256         if (document()->frame())
       
   257             return document()->frame()->eventHandler()->tabsToAllControls(event);
       
   258     return false;
       
   259 }
       
   260 
       
   261 bool HTMLFormControlElement::isMouseFocusable() const
       
   262 {
       
   263 #if PLATFORM(GTK)
       
   264     return HTMLElement::isMouseFocusable();
       
   265 #else
       
   266     return false;
       
   267 #endif
       
   268 }
       
   269 
       
   270 short HTMLFormControlElement::tabIndex() const
       
   271 {
       
   272     // Skip the supportsFocus check in HTMLElement.
       
   273     return Element::tabIndex();
       
   274 }
       
   275 
       
   276 bool HTMLFormControlElement::recalcWillValidate() const
       
   277 {
       
   278     // FIXME: Should return false if this element has a datalist element as an
       
   279     // ancestor. See HTML5 4.10.10 'The datalist element.'
       
   280     return !m_disabled && !m_readOnly;
       
   281 }
       
   282 
       
   283 bool HTMLFormControlElement::willValidate() const
       
   284 {
       
   285     if (!m_willValidateInitialized) {
       
   286         m_willValidateInitialized = true;
       
   287         m_willValidate = recalcWillValidate();
       
   288     } else {
       
   289         // If the following assertion fails, setNeedsWillValidateCheck() is not
       
   290         // called correctly when something which changes recalcWillValidate() result
       
   291         // is updated.
       
   292         ASSERT(m_willValidate == recalcWillValidate());
       
   293     }
       
   294     return m_willValidate;
       
   295 }
       
   296 
       
   297 void HTMLFormControlElement::setNeedsWillValidateCheck()
       
   298 {
       
   299     // We need to recalculate willValidte immediately because willValidate
       
   300     // change can causes style change.
       
   301     bool newWillValidate = recalcWillValidate();
       
   302     if (m_willValidateInitialized && m_willValidate == newWillValidate)
       
   303         return;
       
   304     m_willValidateInitialized = true;
       
   305     m_willValidate = newWillValidate;
       
   306     setNeedsStyleRecalc();
       
   307     // FIXME: Show/hide a validation message.
       
   308 }
       
   309 
       
   310 String HTMLFormControlElement::validationMessage()
       
   311 {
       
   312     return validity()->validationMessage();
       
   313 }
       
   314 
       
   315 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls)
       
   316 {
       
   317     if (!willValidate() || isValidFormControlElement())
       
   318         return true;
       
   319     // An event handler can deref this object.
       
   320     RefPtr<HTMLFormControlElement> protector(this);
       
   321     RefPtr<Document> originalDocument(document());
       
   322     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
       
   323     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
       
   324         unhandledInvalidControls->append(this);
       
   325     return false;
       
   326 }
       
   327 
       
   328 bool HTMLFormControlElement::isValidFormControlElement()
       
   329 {
       
   330     // If the following assertion fails, setNeedsValidityCheck() is not called
       
   331     // correctly when something which changes validity is updated.
       
   332     ASSERT(m_isValid == validity()->valid());
       
   333     return m_isValid;
       
   334 }
       
   335 
       
   336 void HTMLFormControlElement::setNeedsValidityCheck()
       
   337 {
       
   338     bool newIsValid = validity()->valid();
       
   339     if (willValidate() && newIsValid != m_isValid) {
       
   340         // Update style for pseudo classes such as :valid :invalid.
       
   341         setNeedsStyleRecalc();
       
   342     }
       
   343     m_isValid = newIsValid;
       
   344     // FIXME: show/hide a validation message.
       
   345 }
       
   346 
       
   347 void HTMLFormControlElement::setCustomValidity(const String& error)
       
   348 {
       
   349     validity()->setCustomErrorMessage(error);
       
   350 }
       
   351     
       
   352 void HTMLFormControlElement::dispatchFocusEvent()
       
   353 {
       
   354     if (document()->page())
       
   355         document()->page()->chrome()->client()->formDidFocus(this);
       
   356 
       
   357     HTMLElement::dispatchFocusEvent();
       
   358 }
       
   359 
       
   360 void HTMLFormControlElement::dispatchBlurEvent()
       
   361 {
       
   362     if (document()->page())
       
   363         document()->page()->chrome()->client()->formDidBlur(this);
       
   364 
       
   365     HTMLElement::dispatchBlurEvent();
       
   366 }
       
   367 
       
   368 HTMLFormElement* HTMLFormControlElement::virtualForm() const
       
   369 {
       
   370     return m_form;
       
   371 }
       
   372 
       
   373 bool HTMLFormControlElement::isDefaultButtonForForm() const
       
   374 {
       
   375     return isSuccessfulSubmitButton() && m_form && m_form->defaultButton() == this;
       
   376 }
       
   377 
       
   378 void HTMLFormControlElement::removeFromForm()
       
   379 {
       
   380     if (!m_form)
       
   381         return;
       
   382     m_form->removeFormElement(this);
       
   383     m_form = 0;
       
   384 }
       
   385 
       
   386 bool HTMLFormControlElement::isLabelable() const
       
   387 {
       
   388     // FIXME: Add meterTag and outputTag to the list once we support them.
       
   389     return hasTagName(buttonTag) || hasTagName(inputTag) || hasTagName(keygenTag)
       
   390 #if ENABLE(METER_TAG)
       
   391         || hasTagName(meterTag)
       
   392 #endif
       
   393 #if ENABLE(PROGRESS_TAG)
       
   394         || hasTagName(progressTag)
       
   395 #endif
       
   396         || hasTagName(selectTag) || hasTagName(textareaTag);
       
   397 }
       
   398 
       
   399 PassRefPtr<NodeList> HTMLFormControlElement::labels()
       
   400 {
       
   401     if (!isLabelable())
       
   402         return 0;
       
   403     if (!document())
       
   404         return 0;
       
   405     
       
   406     NodeRareData* data = Node::ensureRareData();
       
   407     if (!data->nodeLists()) {
       
   408         data->setNodeLists(NodeListsNodeData::create());
       
   409         document()->addNodeListCache();
       
   410     }
       
   411     
       
   412     return LabelsNodeList::create(this);
       
   413 }
       
   414     
       
   415 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
       
   416     : HTMLFormControlElement(tagName, doc, f)
       
   417 {
       
   418     document()->registerFormElementWithState(this);
       
   419 }
       
   420 
       
   421 HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
       
   422 {
       
   423     document()->unregisterFormElementWithState(this);
       
   424 }
       
   425 
       
   426 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument()
       
   427 {
       
   428     document()->unregisterFormElementWithState(this);
       
   429     HTMLFormControlElement::willMoveToNewOwnerDocument();
       
   430 }
       
   431 
       
   432 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument()
       
   433 {
       
   434     document()->registerFormElementWithState(this);
       
   435     HTMLFormControlElement::didMoveToNewOwnerDocument();
       
   436 }
       
   437 
       
   438 bool HTMLFormControlElementWithState::autoComplete() const
       
   439 {
       
   440     if (!form())
       
   441         return true;
       
   442     return form()->autoComplete();
       
   443 }
       
   444 
       
   445 bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const
       
   446 {
       
   447     // We don't save/restore control state in a form with autocomplete=off.
       
   448     return autoComplete();
       
   449 }
       
   450 
       
   451 void HTMLFormControlElementWithState::finishParsingChildren()
       
   452 {
       
   453     HTMLFormControlElement::finishParsingChildren();
       
   454 
       
   455     // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false.
       
   456     // But we need to skip restoring process too because a control in another
       
   457     // form might have the same pair of name and type and saved its state.
       
   458     if (!shouldSaveAndRestoreFormControlState())
       
   459         return;
       
   460 
       
   461     Document* doc = document();
       
   462     if (doc->hasStateForNewFormElements()) {
       
   463         String state;
       
   464         if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
       
   465             restoreFormControlState(state);
       
   466     }
       
   467 }
       
   468 
       
   469 void HTMLFormControlElementWithState::defaultEventHandler(Event* event)
       
   470 {
       
   471     if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
       
   472         toRenderTextControl(renderer())->subtreeHasChanged();
       
   473         return;
       
   474     }
       
   475 
       
   476     HTMLFormControlElement::defaultEventHandler(event);
       
   477 }
       
   478 
       
   479 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
       
   480     : HTMLFormControlElementWithState(tagName, doc, form)
       
   481 {
       
   482 }
       
   483 
       
   484 HTMLTextFormControlElement::~HTMLTextFormControlElement()
       
   485 {
       
   486 }
       
   487 
       
   488 void HTMLTextFormControlElement::dispatchFocusEvent()
       
   489 {
       
   490     if (supportsPlaceholder())
       
   491         updatePlaceholderVisibility(false);
       
   492     handleFocusEvent();
       
   493     HTMLFormControlElementWithState::dispatchFocusEvent();
       
   494 }
       
   495 
       
   496 void HTMLTextFormControlElement::dispatchBlurEvent()
       
   497 {
       
   498     if (supportsPlaceholder())
       
   499         updatePlaceholderVisibility(false);
       
   500     handleBlurEvent();
       
   501     HTMLFormControlElementWithState::dispatchBlurEvent();
       
   502 }
       
   503 
       
   504 String HTMLTextFormControlElement::strippedPlaceholder() const
       
   505 {
       
   506     // According to the HTML5 specification, we need to remove CR and LF from
       
   507     // the attribute value.
       
   508     const AtomicString& attributeValue = getAttribute(placeholderAttr);
       
   509     if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
       
   510         return attributeValue;
       
   511 
       
   512     Vector<UChar> stripped;
       
   513     unsigned length = attributeValue.length();
       
   514     stripped.reserveCapacity(length);
       
   515     for (unsigned i = 0; i < length; ++i) {
       
   516         UChar character = attributeValue[i];
       
   517         if (character == newlineCharacter || character == carriageReturn)
       
   518             continue;
       
   519         stripped.append(character);
       
   520     }
       
   521     return String::adopt(stripped);
       
   522 }
       
   523 
       
   524 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
       
   525 
       
   526 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
       
   527 {
       
   528     const AtomicString& attributeValue = getAttribute(placeholderAttr);
       
   529     return attributeValue.string().find(isNotLineBreak) == -1;
       
   530 }
       
   531 
       
   532 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
       
   533 {
       
   534     return supportsPlaceholder()
       
   535         && isEmptyValue()
       
   536         && document()->focusedNode() != this
       
   537         && !isPlaceholderEmpty();
       
   538 }
       
   539 
       
   540 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
       
   541 {
       
   542     if (supportsPlaceholder() && renderer())
       
   543         toRenderTextControl(renderer())->updatePlaceholderVisibility(placeholderShouldBeVisible(), placeholderValueChanged);
       
   544 }
       
   545 
       
   546 RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout()
       
   547 {
       
   548     if (!isTextFormControl())
       
   549         return 0;
       
   550     document()->updateLayoutIgnorePendingStylesheets();
       
   551     return toRenderTextControl(renderer());
       
   552 }
       
   553 
       
   554 void HTMLTextFormControlElement::setSelectionStart(int start)
       
   555 {
       
   556     if (RenderTextControl* renderer = textRendererAfterUpdateLayout())
       
   557         renderer->setSelectionStart(start);
       
   558 }
       
   559 
       
   560 void HTMLTextFormControlElement::setSelectionEnd(int end)
       
   561 {
       
   562     if (RenderTextControl* renderer = textRendererAfterUpdateLayout())
       
   563         renderer->setSelectionEnd(end);
       
   564 }
       
   565 
       
   566 void HTMLTextFormControlElement::select()
       
   567 {
       
   568     if (RenderTextControl* renderer = textRendererAfterUpdateLayout())
       
   569         renderer->select();
       
   570 }
       
   571 
       
   572 void HTMLTextFormControlElement::setSelectionRange(int start, int end)
       
   573 {
       
   574     if (RenderTextControl* renderer = textRendererAfterUpdateLayout())
       
   575         renderer->setSelectionRange(start, end);
       
   576 }
       
   577 
       
   578 int HTMLTextFormControlElement::selectionStart()
       
   579 {
       
   580     if (!isTextFormControl())
       
   581         return 0;
       
   582     if (document()->focusedNode() != this && cachedSelectionStart() >= 0)
       
   583         return cachedSelectionStart();
       
   584     if (!renderer())
       
   585         return 0;
       
   586     return toRenderTextControl(renderer())->selectionStart();
       
   587 }
       
   588 
       
   589 int HTMLTextFormControlElement::selectionEnd()
       
   590 {
       
   591     if (!isTextFormControl())
       
   592         return 0;
       
   593     if (document()->focusedNode() != this && cachedSelectionEnd() >= 0)
       
   594         return cachedSelectionEnd();
       
   595     if (!renderer())
       
   596         return 0;
       
   597     return toRenderTextControl(renderer())->selectionEnd();
       
   598 }
       
   599 
       
   600 VisibleSelection HTMLTextFormControlElement::selection() const
       
   601 {
       
   602     if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0)
       
   603         return VisibleSelection();
       
   604     return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd());
       
   605 }
       
   606 
       
   607 void HTMLTextFormControlElement::parseMappedAttribute(Attribute* attr)
       
   608 {
       
   609     if (attr->name() == placeholderAttr)
       
   610         updatePlaceholderVisibility(true);
       
   611     else if (attr->name() == onselectAttr)
       
   612         setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr));
       
   613     else if (attr->name() == onchangeAttr)
       
   614         setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr));
       
   615     else
       
   616         HTMLFormControlElementWithState::parseMappedAttribute(attr);
       
   617 }
       
   618 
       
   619 } // namespace Webcore