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