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