Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
      6  *           (C) 2006 Alexey Proskuryakov (ap (at) 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 "core/html/HTMLFormControlElement.h"
     27 
     28 #include "core/dom/Event.h"
     29 #include "core/dom/EventNames.h"
     30 #include "core/html/HTMLFieldSetElement.h"
     31 #include "core/html/HTMLFormElement.h"
     32 #include "core/html/HTMLInputElement.h"
     33 #include "core/html/HTMLLegendElement.h"
     34 #include "core/html/HTMLTextAreaElement.h"
     35 #include "core/html/ValidationMessage.h"
     36 #include "core/html/ValidityState.h"
     37 #include "core/page/UseCounter.h"
     38 #include "core/rendering/RenderBox.h"
     39 #include "core/rendering/RenderTheme.h"
     40 #include "wtf/Vector.h"
     41 
     42 namespace WebCore {
     43 
     44 using namespace HTMLNames;
     45 using namespace std;
     46 
     47 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
     48     : LabelableElement(tagName, document)
     49     , m_disabled(false)
     50     , m_isReadOnly(false)
     51     , m_isRequired(false)
     52     , m_valueMatchesRenderer(false)
     53     , m_ancestorDisabledState(AncestorDisabledStateUnknown)
     54     , m_dataListAncestorState(Unknown)
     55     , m_willValidateInitialized(false)
     56     , m_willValidate(true)
     57     , m_isValid(true)
     58     , m_wasChangedSinceLastFormControlChangeEvent(false)
     59     , m_wasFocusedByMouse(false)
     60     , m_hasAutofocused(false)
     61 {
     62     setForm(form ? form : findFormAncestor());
     63     setHasCustomStyleCallbacks();
     64 }
     65 
     66 HTMLFormControlElement::~HTMLFormControlElement()
     67 {
     68 }
     69 
     70 String HTMLFormControlElement::formEnctype() const
     71 {
     72     const AtomicString& formEnctypeAttr = fastGetAttribute(formenctypeAttr);
     73     if (formEnctypeAttr.isNull())
     74         return emptyString();
     75     return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr);
     76 }
     77 
     78 void HTMLFormControlElement::setFormEnctype(const String& value)
     79 {
     80     setAttribute(formenctypeAttr, value);
     81 }
     82 
     83 String HTMLFormControlElement::formMethod() const
     84 {
     85     const AtomicString& formMethodAttr = fastGetAttribute(formmethodAttr);
     86     if (formMethodAttr.isNull())
     87         return emptyString();
     88     return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr));
     89 }
     90 
     91 void HTMLFormControlElement::setFormMethod(const String& value)
     92 {
     93     setAttribute(formmethodAttr, value);
     94 }
     95 
     96 bool HTMLFormControlElement::formNoValidate() const
     97 {
     98     return fastHasAttribute(formnovalidateAttr);
     99 }
    100 
    101 void HTMLFormControlElement::updateAncestorDisabledState() const
    102 {
    103     HTMLFieldSetElement* fieldSetAncestor = 0;
    104     ContainerNode* legendAncestor = 0;
    105     for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
    106         if (!legendAncestor && ancestor->hasTagName(legendTag))
    107             legendAncestor = ancestor;
    108         if (ancestor->hasTagName(fieldsetTag)) {
    109             fieldSetAncestor = static_cast<HTMLFieldSetElement*>(ancestor);
    110             break;
    111         }
    112     }
    113     m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->isDisabledFormControl() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled;
    114 }
    115 
    116 void HTMLFormControlElement::ancestorDisabledStateWasChanged()
    117 {
    118     m_ancestorDisabledState = AncestorDisabledStateUnknown;
    119     disabledAttributeChanged();
    120 }
    121 
    122 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    123 {
    124     if (name == formAttr) {
    125         formAttributeChanged();
    126         UseCounter::count(document(), UseCounter::FormAttribute);
    127     } else if (name == disabledAttr) {
    128         bool oldDisabled = m_disabled;
    129         m_disabled = !value.isNull();
    130         if (oldDisabled != m_disabled)
    131             disabledAttributeChanged();
    132     } else if (name == readonlyAttr) {
    133         bool wasReadOnly = m_isReadOnly;
    134         m_isReadOnly = !value.isNull();
    135         if (wasReadOnly != m_isReadOnly) {
    136             setNeedsWillValidateCheck();
    137             setNeedsStyleRecalc();
    138             if (renderer() && renderer()->style()->hasAppearance())
    139                 renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
    140         }
    141     } else if (name == requiredAttr) {
    142         bool wasRequired = m_isRequired;
    143         m_isRequired = !value.isNull();
    144         if (wasRequired != m_isRequired)
    145             requiredAttributeChanged();
    146         UseCounter::count(document(), UseCounter::RequiredAttribute);
    147     } else if (name == autofocusAttr) {
    148         HTMLElement::parseAttribute(name, value);
    149         UseCounter::count(document(), UseCounter::AutoFocusAttribute);
    150     } else
    151         HTMLElement::parseAttribute(name, value);
    152 }
    153 
    154 void HTMLFormControlElement::disabledAttributeChanged()
    155 {
    156     setNeedsWillValidateCheck();
    157     didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled);
    158     if (renderer() && renderer()->style()->hasAppearance())
    159         renderer()->theme()->stateChanged(renderer(), EnabledState);
    160     if (isDisabledFormControl() && treeScope()->adjustedFocusedElement() == this) {
    161         // We might want to call blur(), but it's dangerous to dispatch events
    162         // here.
    163         document()->setNeedsFocusedElementCheck();
    164     }
    165 }
    166 
    167 void HTMLFormControlElement::requiredAttributeChanged()
    168 {
    169     setNeedsValidityCheck();
    170     // Style recalculation is needed because style selectors may include
    171     // :required and :optional pseudo-classes.
    172     setNeedsStyleRecalc();
    173 }
    174 
    175 static bool shouldAutofocus(HTMLFormControlElement* element)
    176 {
    177     if (!element->fastHasAttribute(autofocusAttr))
    178         return false;
    179     if (!element->renderer())
    180         return false;
    181     if (element->document()->ignoreAutofocus())
    182         return false;
    183     if (element->document()->isSandboxed(SandboxAutomaticFeatures)) {
    184         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
    185         element->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set.");
    186         return false;
    187     }
    188     if (element->hasAutofocused())
    189         return false;
    190 
    191     // FIXME: Should this set of hasTagName checks be replaced by a
    192     // virtual member function?
    193     if (element->hasTagName(inputTag))
    194         return !toHTMLInputElement(element)->isInputTypeHidden();
    195     if (element->hasTagName(selectTag))
    196         return true;
    197     if (element->hasTagName(keygenTag))
    198         return true;
    199     if (element->hasTagName(buttonTag))
    200         return true;
    201     if (isHTMLTextAreaElement(element))
    202         return true;
    203 
    204     return false;
    205 }
    206 
    207 static void focusPostAttach(Node* element)
    208 {
    209     toElement(element)->focus();
    210     element->deref();
    211 }
    212 
    213 void HTMLFormControlElement::attach(const AttachContext& context)
    214 {
    215     PostAttachCallbackDisabler disabler(this);
    216 
    217     HTMLElement::attach(context);
    218 
    219     // The call to updateFromElement() needs to go after the call through
    220     // to the base class's attach() because that can sometimes do a close
    221     // on the renderer.
    222     if (renderer())
    223         renderer()->updateFromElement();
    224 
    225     if (shouldAutofocus(this)) {
    226         setAutofocused();
    227         ref();
    228         queuePostAttachCallback(focusPostAttach, this);
    229     }
    230 }
    231 
    232 void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
    233 {
    234     FormAssociatedElement::didMoveToNewDocument(oldDocument);
    235     HTMLElement::didMoveToNewDocument(oldDocument);
    236 }
    237 
    238 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
    239 {
    240     m_ancestorDisabledState = AncestorDisabledStateUnknown;
    241     m_dataListAncestorState = Unknown;
    242     setNeedsWillValidateCheck();
    243     HTMLElement::insertedInto(insertionPoint);
    244     FormAssociatedElement::insertedInto(insertionPoint);
    245     return InsertionDone;
    246 }
    247 
    248 void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
    249 {
    250     m_validationMessage = nullptr;
    251     m_ancestorDisabledState = AncestorDisabledStateUnknown;
    252     m_dataListAncestorState = Unknown;
    253     HTMLElement::removedFrom(insertionPoint);
    254     FormAssociatedElement::removedFrom(insertionPoint);
    255 }
    256 
    257 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
    258 {
    259     return m_wasChangedSinceLastFormControlChangeEvent;
    260 }
    261 
    262 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
    263 {
    264     m_wasChangedSinceLastFormControlChangeEvent = changed;
    265 }
    266 
    267 void HTMLFormControlElement::dispatchFormControlChangeEvent()
    268 {
    269     HTMLElement::dispatchChangeEvent();
    270     setChangedSinceLastFormControlChangeEvent(false);
    271 }
    272 
    273 void HTMLFormControlElement::dispatchFormControlInputEvent()
    274 {
    275     setChangedSinceLastFormControlChangeEvent(true);
    276     HTMLElement::dispatchInputEvent();
    277 }
    278 
    279 bool HTMLFormControlElement::isDisabledFormControl() const
    280 {
    281     if (m_disabled)
    282         return true;
    283 
    284     if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
    285         updateAncestorDisabledState();
    286     return m_ancestorDisabledState == AncestorDisabledStateDisabled;
    287 }
    288 
    289 bool HTMLFormControlElement::isRequired() const
    290 {
    291     return m_isRequired;
    292 }
    293 
    294 static void updateFromElementCallback(Node* node)
    295 {
    296     ASSERT_ARG(node, node->isElementNode());
    297     ASSERT_ARG(node, toElement(node)->isFormControlElement());
    298     if (RenderObject* renderer = node->renderer())
    299         renderer->updateFromElement();
    300 }
    301 
    302 void HTMLFormControlElement::didRecalcStyle(StyleChange)
    303 {
    304     // updateFromElement() can cause the selection to change, and in turn
    305     // trigger synchronous layout, so it must not be called during style recalc.
    306     if (renderer())
    307         queuePostAttachCallback(updateFromElementCallback, this);
    308 }
    309 
    310 bool HTMLFormControlElement::supportsFocus() const
    311 {
    312     return !isDisabledFormControl();
    313 }
    314 
    315 bool HTMLFormControlElement::rendererIsFocusable() const
    316 {
    317     // If there's a renderer, make sure the size isn't empty, but if there's no renderer,
    318     // it might still be focusable if it's in a canvas subtree (handled in Element::rendererIsFocusable).
    319     if (renderer() && (!renderer()->isBox() || toRenderBox(renderer())->size().isEmpty()))
    320         return false;
    321     return HTMLElement::rendererIsFocusable();
    322 }
    323 
    324 bool HTMLFormControlElement::isKeyboardFocusable() const
    325 {
    326     // Skip tabIndex check in a parent class.
    327     return isFocusable();
    328 }
    329 
    330 bool HTMLFormControlElement::shouldShowFocusRingOnMouseFocus() const
    331 {
    332     return false;
    333 }
    334 
    335 void HTMLFormControlElement::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection direction)
    336 {
    337     if (direction != FocusDirectionPage)
    338         m_wasFocusedByMouse = direction == FocusDirectionMouse;
    339     HTMLElement::dispatchFocusEvent(oldFocusedElement, direction);
    340 }
    341 
    342 bool HTMLFormControlElement::shouldHaveFocusAppearance() const
    343 {
    344     ASSERT(focused());
    345     return shouldShowFocusRingOnMouseFocus() || !m_wasFocusedByMouse;
    346 }
    347 
    348 void HTMLFormControlElement::willCallDefaultEventHandler(const Event& event)
    349 {
    350     if (!event.isKeyboardEvent() || event.type() != eventNames().keydownEvent)
    351         return;
    352     if (!m_wasFocusedByMouse)
    353         return;
    354     m_wasFocusedByMouse = false;
    355     if (renderer())
    356         renderer()->repaint();
    357 }
    358 
    359 
    360 short HTMLFormControlElement::tabIndex() const
    361 {
    362     // Skip the supportsFocus check in HTMLElement.
    363     return Element::tabIndex();
    364 }
    365 
    366 bool HTMLFormControlElement::recalcWillValidate() const
    367 {
    368     if (m_dataListAncestorState == Unknown) {
    369         for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
    370             if (ancestor->hasTagName(datalistTag)) {
    371                 m_dataListAncestorState = InsideDataList;
    372                 break;
    373             }
    374         }
    375         if (m_dataListAncestorState == Unknown)
    376             m_dataListAncestorState = NotInsideDataList;
    377     }
    378     return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
    379 }
    380 
    381 bool HTMLFormControlElement::willValidate() const
    382 {
    383     if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
    384         m_willValidateInitialized = true;
    385         bool newWillValidate = recalcWillValidate();
    386         if (m_willValidate != newWillValidate) {
    387             m_willValidate = newWillValidate;
    388             const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck();
    389         }
    390     } else {
    391         // If the following assertion fails, setNeedsWillValidateCheck() is not
    392         // called correctly when something which changes recalcWillValidate() result
    393         // is updated.
    394         ASSERT(m_willValidate == recalcWillValidate());
    395     }
    396     return m_willValidate;
    397 }
    398 
    399 void HTMLFormControlElement::setNeedsWillValidateCheck()
    400 {
    401     // We need to recalculate willValidate immediately because willValidate change can causes style change.
    402     bool newWillValidate = recalcWillValidate();
    403     if (m_willValidateInitialized && m_willValidate == newWillValidate)
    404         return;
    405     m_willValidateInitialized = true;
    406     m_willValidate = newWillValidate;
    407     setNeedsValidityCheck();
    408     setNeedsStyleRecalc();
    409     if (!m_willValidate)
    410         hideVisibleValidationMessage();
    411 }
    412 
    413 void HTMLFormControlElement::updateVisibleValidationMessage()
    414 {
    415     Page* page = document()->page();
    416     if (!page)
    417         return;
    418     String message;
    419     if (renderer() && willValidate())
    420         message = validationMessage().stripWhiteSpace();
    421     if (!m_validationMessage)
    422         m_validationMessage = ValidationMessage::create(this);
    423     m_validationMessage->updateValidationMessage(message);
    424 }
    425 
    426 void HTMLFormControlElement::hideVisibleValidationMessage()
    427 {
    428     if (m_validationMessage)
    429         m_validationMessage->requestToHideMessage();
    430 }
    431 
    432 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls, CheckValidityDispatchEvents dispatchEvents)
    433 {
    434     // START ANDROID WEBVIEW WORKAROUND -- see b/10621067
    435     return true;
    436     // END ANDROID WEBVIEW WORKAROUND
    437 
    438     if (!willValidate() || isValidFormControlElement())
    439         return true;
    440     if (dispatchEvents == CheckValidityDispatchEventsNone)
    441         return false;
    442     // An event handler can deref this object.
    443     RefPtr<HTMLFormControlElement> protector(this);
    444     RefPtr<Document> originalDocument(document());
    445     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
    446     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
    447         unhandledInvalidControls->append(this);
    448     return false;
    449 }
    450 
    451 bool HTMLFormControlElement::isValidFormControlElement()
    452 {
    453     // If the following assertion fails, setNeedsValidityCheck() is not called
    454     // correctly when something which changes validity is updated.
    455     ASSERT(m_isValid == validity()->valid());
    456     return m_isValid;
    457 }
    458 
    459 void HTMLFormControlElement::setNeedsValidityCheck()
    460 {
    461     bool newIsValid = validity()->valid();
    462     if (willValidate() && newIsValid != m_isValid) {
    463         // Update style for pseudo classes such as :valid :invalid.
    464         setNeedsStyleRecalc();
    465     }
    466     m_isValid = newIsValid;
    467 
    468     // Updates only if this control already has a validtion message.
    469     if (m_validationMessage && m_validationMessage->isVisible()) {
    470         // Calls updateVisibleValidationMessage() even if m_isValid is not
    471         // changed because a validation message can be chagned.
    472         updateVisibleValidationMessage();
    473     }
    474 }
    475 
    476 void HTMLFormControlElement::setCustomValidity(const String& error)
    477 {
    478     FormAssociatedElement::setCustomValidity(error);
    479     setNeedsValidityCheck();
    480 }
    481 
    482 void HTMLFormControlElement::dispatchBlurEvent(Element* newFocusedElement)
    483 {
    484     HTMLElement::dispatchBlurEvent(newFocusedElement);
    485     hideVisibleValidationMessage();
    486 }
    487 
    488 HTMLFormElement* HTMLFormControlElement::virtualForm() const
    489 {
    490     return FormAssociatedElement::form();
    491 }
    492 
    493 bool HTMLFormControlElement::isDefaultButtonForForm() const
    494 {
    495     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
    496 }
    497 
    498 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
    499 {
    500     for (; node; node = node->parentNode()) {
    501         if (node->isElementNode() && toElement(node)->isFormControlElement())
    502             return toHTMLFormControlElement(node);
    503     }
    504     return 0;
    505 }
    506 
    507 } // namespace Webcore
    508