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