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, 2008, 2009 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/HTMLFormElement.h"
     27 
     28 #include <limits>
     29 #include "HTMLNames.h"
     30 #include "bindings/v8/ScriptController.h"
     31 #include "bindings/v8/ScriptEventListener.h"
     32 #include "core/dom/Attribute.h"
     33 #include "core/dom/AutocompleteErrorEvent.h"
     34 #include "core/dom/Document.h"
     35 #include "core/dom/Event.h"
     36 #include "core/dom/EventNames.h"
     37 #include "core/dom/NamedNodesCollection.h"
     38 #include "core/dom/NodeRenderingContext.h"
     39 #include "core/dom/NodeTraversal.h"
     40 #include "core/html/FormController.h"
     41 #include "core/html/HTMLCollection.h"
     42 #include "core/html/HTMLImageElement.h"
     43 #include "core/html/HTMLInputElement.h"
     44 #include "core/html/HTMLTableElement.h"
     45 #include "core/loader/FormState.h"
     46 #include "core/loader/FrameLoader.h"
     47 #include "core/loader/FrameLoaderClient.h"
     48 #include "core/page/Frame.h"
     49 #include "core/page/UseCounter.h"
     50 #include "core/rendering/RenderTextControl.h"
     51 
     52 using namespace std;
     53 
     54 namespace WebCore {
     55 
     56 using namespace HTMLNames;
     57 
     58 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
     59     : HTMLElement(tagName, document)
     60     , m_associatedElementsBeforeIndex(0)
     61     , m_associatedElementsAfterIndex(0)
     62     , m_wasUserSubmitted(false)
     63     , m_isSubmittingOrPreparingForSubmission(false)
     64     , m_shouldSubmit(false)
     65     , m_isInResetFunction(false)
     66     , m_wasDemoted(false)
     67     , m_requestAutocompleteTimer(this, &HTMLFormElement::requestAutocompleteTimerFired)
     68 {
     69     ASSERT(hasTagName(formTag));
     70     ScriptWrappable::init(this);
     71 }
     72 
     73 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
     74 {
     75     UseCounter::count(document, UseCounter::FormElement);
     76     return adoptRef(new HTMLFormElement(formTag, document));
     77 }
     78 
     79 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
     80 {
     81     UseCounter::count(document, UseCounter::FormElement);
     82     return adoptRef(new HTMLFormElement(tagName, document));
     83 }
     84 
     85 HTMLFormElement::~HTMLFormElement()
     86 {
     87     document()->formController()->willDeleteForm(this);
     88 
     89     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
     90         m_associatedElements[i]->formWillBeDestroyed();
     91     for (unsigned i = 0; i < m_imageElements.size(); ++i)
     92         m_imageElements[i]->m_form = 0;
     93 }
     94 
     95 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
     96 {
     97     return document()->completeURL(url).protocolIs("https");
     98 }
     99 
    100 bool HTMLFormElement::rendererIsNeeded(const NodeRenderingContext& context)
    101 {
    102     if (!m_wasDemoted)
    103         return HTMLElement::rendererIsNeeded(context);
    104 
    105     ContainerNode* node = parentNode();
    106     RenderObject* parentRenderer = node->renderer();
    107     // FIXME: Shouldn't we also check for table caption (see |formIsTablePart| below).
    108     bool parentIsTableElementPart = (parentRenderer->isTable() && isHTMLTableElement(node))
    109         || (parentRenderer->isTableRow() && node->hasTagName(trTag))
    110         || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
    111         || (parentRenderer->isRenderTableCol() && node->hasTagName(colTag))
    112         || (parentRenderer->isTableCell() && node->hasTagName(trTag));
    113 
    114     if (!parentIsTableElementPart)
    115         return true;
    116 
    117     EDisplay display = context.style()->display();
    118     bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
    119         || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
    120         || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
    121         || display == TABLE_CAPTION;
    122 
    123     return formIsTablePart;
    124 }
    125 
    126 Node::InsertionNotificationRequest HTMLFormElement::insertedInto(ContainerNode* insertionPoint)
    127 {
    128     HTMLElement::insertedInto(insertionPoint);
    129     if (insertionPoint->inDocument())
    130         this->document()->didAssociateFormControl(this);
    131     return InsertionDone;
    132 }
    133 
    134 static inline Node* findRoot(Node* n)
    135 {
    136     Node* root = n;
    137     for (; n; n = n->parentNode())
    138         root = n;
    139     return root;
    140 }
    141 
    142 void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
    143 {
    144     Node* root = findRoot(this);
    145     Vector<FormAssociatedElement*> associatedElements(m_associatedElements);
    146     for (unsigned i = 0; i < associatedElements.size(); ++i)
    147         associatedElements[i]->formRemovedFromTree(root);
    148     HTMLElement::removedFrom(insertionPoint);
    149 }
    150 
    151 void HTMLFormElement::handleLocalEvents(Event* event)
    152 {
    153     Node* targetNode = event->target()->toNode();
    154     if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
    155         event->stopPropagation();
    156         return;
    157     }
    158     HTMLElement::handleLocalEvents(event);
    159 }
    160 
    161 unsigned HTMLFormElement::length() const
    162 {
    163     unsigned len = 0;
    164     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
    165         if (m_associatedElements[i]->isEnumeratable())
    166             ++len;
    167     return len;
    168 }
    169 
    170 Node* HTMLFormElement::item(unsigned index)
    171 {
    172     return elements()->item(index);
    173 }
    174 
    175 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
    176 {
    177     int submissionTriggerCount = 0;
    178     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
    179         FormAssociatedElement* formAssociatedElement = m_associatedElements[i];
    180         if (!formAssociatedElement->isFormControlElement())
    181             continue;
    182         HTMLFormControlElement* control = toHTMLFormControlElement(formAssociatedElement);
    183         if (control->isSuccessfulSubmitButton()) {
    184             if (control->renderer()) {
    185                 control->dispatchSimulatedClick(event);
    186                 return;
    187             }
    188         } else if (control->canTriggerImplicitSubmission())
    189             ++submissionTriggerCount;
    190     }
    191     if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
    192         prepareForSubmission(event);
    193 }
    194 
    195 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
    196 {
    197     for (Node* node = event->target()->toNode(); node; node = node->parentNode()) {
    198         if (node->isElementNode() && toElement(node)->isFormControlElement())
    199             return toHTMLFormControlElement(node);
    200     }
    201     return 0;
    202 }
    203 
    204 bool HTMLFormElement::validateInteractively(Event* event)
    205 {
    206     ASSERT(event);
    207     if (!document()->page() || noValidate())
    208         return true;
    209 
    210     HTMLFormControlElement* submitElement = submitElementFromEvent(event);
    211     if (submitElement && submitElement->formNoValidate())
    212         return true;
    213 
    214     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
    215         if (m_associatedElements[i]->isFormControlElement())
    216             toHTMLFormControlElement(m_associatedElements[i])->hideVisibleValidationMessage();
    217     }
    218 
    219     Vector<RefPtr<FormAssociatedElement> > unhandledInvalidControls;
    220     if (!checkInvalidControlsAndCollectUnhandled(&unhandledInvalidControls))
    221         return true;
    222     // Because the form has invalid controls, we abort the form submission and
    223     // show a validation message on a focusable form control.
    224 
    225     // Needs to update layout now because we'd like to call isFocusable(), which
    226     // has !renderer()->needsLayout() assertion.
    227     document()->updateLayoutIgnorePendingStylesheets();
    228 
    229     RefPtr<HTMLFormElement> protector(this);
    230     // Focus on the first focusable control and show a validation message.
    231     for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
    232         FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
    233         HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
    234         if (unhandled->isFocusable() && unhandled->inDocument()) {
    235             unhandled->scrollIntoViewIfNeeded(false);
    236             unhandled->focus();
    237             if (unhandled->isFormControlElement())
    238                 toHTMLFormControlElement(unhandled)->updateVisibleValidationMessage();
    239             break;
    240         }
    241     }
    242     // Warn about all of unfocusable controls.
    243     if (document()->frame()) {
    244         for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
    245             FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
    246             HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
    247             if (unhandled->isFocusable() && unhandled->inDocument())
    248                 continue;
    249             String message("An invalid form control with name='%name' is not focusable.");
    250             message.replace("%name", unhandledAssociatedElement->name());
    251             document()->addConsoleMessage(RenderingMessageSource, ErrorMessageLevel, message);
    252         }
    253     }
    254     return false;
    255 }
    256 
    257 bool HTMLFormElement::prepareForSubmission(Event* event)
    258 {
    259     RefPtr<HTMLFormElement> protector(this);
    260     Frame* frame = document()->frame();
    261     if (m_isSubmittingOrPreparingForSubmission || !frame)
    262         return m_isSubmittingOrPreparingForSubmission;
    263 
    264     m_isSubmittingOrPreparingForSubmission = true;
    265     m_shouldSubmit = false;
    266 
    267     // Interactive validation must be done before dispatching the submit event.
    268     if (!validateInteractively(event)) {
    269         m_isSubmittingOrPreparingForSubmission = false;
    270         return false;
    271     }
    272 
    273     StringPairVector controlNamesAndValues;
    274     getTextFieldValues(controlNamesAndValues);
    275     RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), NotSubmittedByJavaScript);
    276     frame->loader()->client()->dispatchWillSendSubmitEvent(formState.release());
    277 
    278     if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
    279         m_shouldSubmit = true;
    280 
    281     m_isSubmittingOrPreparingForSubmission = false;
    282 
    283     if (m_shouldSubmit)
    284         submit(event, true, true, NotSubmittedByJavaScript);
    285 
    286     return m_shouldSubmit;
    287 }
    288 
    289 void HTMLFormElement::submit()
    290 {
    291     submit(0, false, true, NotSubmittedByJavaScript);
    292 }
    293 
    294 void HTMLFormElement::submitFromJavaScript()
    295 {
    296     submit(0, false, ScriptController::processingUserGesture(), SubmittedByJavaScript);
    297 }
    298 
    299 void HTMLFormElement::getTextFieldValues(StringPairVector& fieldNamesAndValues) const
    300 {
    301     ASSERT_ARG(fieldNamesAndValues, fieldNamesAndValues.isEmpty());
    302 
    303     fieldNamesAndValues.reserveCapacity(m_associatedElements.size());
    304     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
    305         FormAssociatedElement* control = m_associatedElements[i];
    306         HTMLElement* element = toHTMLElement(control);
    307         if (!element->hasTagName(inputTag))
    308             continue;
    309 
    310         HTMLInputElement* input = toHTMLInputElement(element);
    311         if (!input->isTextField())
    312             continue;
    313 
    314         fieldNamesAndValues.append(make_pair(input->name().string(), input->value()));
    315     }
    316 }
    317 
    318 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
    319 {
    320     FrameView* view = document()->view();
    321     Frame* frame = document()->frame();
    322     if (!view || !frame)
    323         return;
    324 
    325     if (m_isSubmittingOrPreparingForSubmission) {
    326         m_shouldSubmit = true;
    327         return;
    328     }
    329 
    330     m_isSubmittingOrPreparingForSubmission = true;
    331     m_wasUserSubmitted = processingUserGesture;
    332 
    333     RefPtr<HTMLFormControlElement> firstSuccessfulSubmitButton;
    334     bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
    335 
    336     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
    337         FormAssociatedElement* associatedElement = m_associatedElements[i];
    338         if (!associatedElement->isFormControlElement())
    339             continue;
    340         if (needButtonActivation) {
    341             HTMLFormControlElement* control = toHTMLFormControlElement(associatedElement);
    342             if (control->isActivatedSubmit())
    343                 needButtonActivation = false;
    344             else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
    345                 firstSuccessfulSubmitButton = control;
    346         }
    347     }
    348 
    349     if (needButtonActivation && firstSuccessfulSubmitButton)
    350         firstSuccessfulSubmitButton->setActivatedSubmit(true);
    351 
    352     frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, formSubmissionTrigger));
    353 
    354     if (needButtonActivation && firstSuccessfulSubmitButton)
    355         firstSuccessfulSubmitButton->setActivatedSubmit(false);
    356 
    357     m_shouldSubmit = false;
    358     m_isSubmittingOrPreparingForSubmission = false;
    359 }
    360 
    361 void HTMLFormElement::reset()
    362 {
    363     Frame* frame = document()->frame();
    364     if (m_isInResetFunction || !frame)
    365         return;
    366 
    367     m_isInResetFunction = true;
    368 
    369     if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
    370         m_isInResetFunction = false;
    371         return;
    372     }
    373 
    374     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
    375         if (m_associatedElements[i]->isFormControlElement())
    376             toHTMLFormControlElement(m_associatedElements[i])->reset();
    377     }
    378 
    379     m_isInResetFunction = false;
    380 }
    381 
    382 void HTMLFormElement::requestAutocomplete()
    383 {
    384     Frame* frame = document()->frame();
    385     if (!frame)
    386         return;
    387 
    388     if (!shouldAutocomplete() || !ScriptController::processingUserGesture()) {
    389         finishRequestAutocomplete(AutocompleteResultErrorDisabled);
    390         return;
    391     }
    392 
    393     StringPairVector controlNamesAndValues;
    394     getTextFieldValues(controlNamesAndValues);
    395     RefPtr<FormState> formState = FormState::create(this, controlNamesAndValues, document(), SubmittedByJavaScript);
    396     frame->loader()->client()->didRequestAutocomplete(formState.release());
    397 }
    398 
    399 void HTMLFormElement::finishRequestAutocomplete(AutocompleteResult result)
    400 {
    401     RefPtr<Event> event;
    402     if (result == AutocompleteResultSuccess)
    403         event = Event::create(eventNames().autocompleteEvent, false, false);
    404     else if (result == AutocompleteResultErrorDisabled)
    405         event = AutocompleteErrorEvent::create("disabled");
    406     else if (result == AutocompleteResultErrorCancel)
    407         event = AutocompleteErrorEvent::create("cancel");
    408     else if (result == AutocompleteResultErrorInvalid)
    409         event = AutocompleteErrorEvent::create("invalid");
    410 
    411     event->setTarget(this);
    412     m_pendingAutocompleteEvents.append(event.release());
    413 
    414     // Dispatch events later as this API is meant to work asynchronously in all situations and implementations.
    415     if (!m_requestAutocompleteTimer.isActive())
    416         m_requestAutocompleteTimer.startOneShot(0);
    417 }
    418 
    419 void HTMLFormElement::requestAutocompleteTimerFired(Timer<HTMLFormElement>*)
    420 {
    421     Vector<RefPtr<Event> > pendingEvents;
    422     m_pendingAutocompleteEvents.swap(pendingEvents);
    423     for (size_t i = 0; i < pendingEvents.size(); ++i)
    424         dispatchEvent(pendingEvents[i].release());
    425 }
    426 
    427 void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    428 {
    429     if (name == actionAttr)
    430         m_attributes.parseAction(value);
    431     else if (name == targetAttr)
    432         m_attributes.setTarget(value);
    433     else if (name == methodAttr)
    434         m_attributes.updateMethodType(value);
    435     else if (name == enctypeAttr)
    436         m_attributes.updateEncodingType(value);
    437     else if (name == accept_charsetAttr)
    438         m_attributes.setAcceptCharset(value);
    439     else if (name == onautocompleteAttr)
    440         setAttributeEventListener(eventNames().autocompleteEvent, createAttributeEventListener(this, name, value));
    441     else if (name == onautocompleteerrorAttr)
    442         setAttributeEventListener(eventNames().autocompleteerrorEvent, createAttributeEventListener(this, name, value));
    443     else
    444         HTMLElement::parseAttribute(name, value);
    445 }
    446 
    447 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
    448 {
    449     size_t size = vec.size();
    450     for (size_t i = 0; i != size; ++i)
    451         if (vec[i] == item) {
    452             vec.remove(i);
    453             break;
    454         }
    455 }
    456 
    457 unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element, unsigned rangeStart, unsigned rangeEnd)
    458 {
    459     if (m_associatedElements.isEmpty())
    460         return 0;
    461 
    462     ASSERT(rangeStart <= rangeEnd);
    463 
    464     if (rangeStart == rangeEnd)
    465         return rangeStart;
    466 
    467     unsigned left = rangeStart;
    468     unsigned right = rangeEnd - 1;
    469     unsigned short position;
    470 
    471     // Does binary search on m_associatedElements in order to find the index
    472     // to be inserted.
    473     while (left != right) {
    474         unsigned middle = left + ((right - left) / 2);
    475         ASSERT(middle < m_associatedElementsBeforeIndex || middle >= m_associatedElementsAfterIndex);
    476         position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
    477         if (position & DOCUMENT_POSITION_FOLLOWING)
    478             right = middle;
    479         else
    480             left = middle + 1;
    481     }
    482 
    483     ASSERT(left < m_associatedElementsBeforeIndex || left >= m_associatedElementsAfterIndex);
    484     position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
    485     if (position & DOCUMENT_POSITION_FOLLOWING)
    486         return left;
    487     return left + 1;
    488 }
    489 
    490 unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
    491 {
    492     HTMLElement* associatedHTMLElement = toHTMLElement(associatedElement);
    493     // Treats separately the case where this element has the form attribute
    494     // for performance consideration.
    495     if (associatedHTMLElement->fastHasAttribute(formAttr)) {
    496         unsigned short position = compareDocumentPosition(associatedHTMLElement);
    497         if (position & DOCUMENT_POSITION_PRECEDING) {
    498             ++m_associatedElementsBeforeIndex;
    499             ++m_associatedElementsAfterIndex;
    500             return HTMLFormElement::formElementIndexWithFormAttribute(associatedHTMLElement, 0, m_associatedElementsBeforeIndex - 1);
    501         }
    502         if (position & DOCUMENT_POSITION_FOLLOWING && !(position & DOCUMENT_POSITION_CONTAINED_BY))
    503             return HTMLFormElement::formElementIndexWithFormAttribute(associatedHTMLElement, m_associatedElementsAfterIndex, m_associatedElements.size());
    504     }
    505 
    506     // Check for the special case where this element is the very last thing in
    507     // the form's tree of children; we don't want to walk the entire tree in that
    508     // common case that occurs during parsing; instead we'll just return a value
    509     // that says "add this form element to the end of the array".
    510     if (ElementTraversal::next(associatedHTMLElement, this)) {
    511         unsigned i = m_associatedElementsBeforeIndex;
    512         for (Element* element = this; element; element = ElementTraversal::next(element, this)) {
    513             if (element == associatedHTMLElement) {
    514                 ++m_associatedElementsAfterIndex;
    515                 return i;
    516             }
    517             if (!element->isFormControlElement() && !element->hasTagName(objectTag))
    518                 continue;
    519             if (!element->isHTMLElement() || toHTMLElement(element)->form() != this)
    520                 continue;
    521             ++i;
    522         }
    523     }
    524     return m_associatedElementsAfterIndex++;
    525 }
    526 
    527 void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
    528 {
    529     m_associatedElements.insert(formElementIndex(e), e);
    530 }
    531 
    532 void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
    533 {
    534     unsigned index;
    535     for (index = 0; index < m_associatedElements.size(); ++index) {
    536         if (m_associatedElements[index] == e)
    537             break;
    538     }
    539     ASSERT_WITH_SECURITY_IMPLICATION(index < m_associatedElements.size());
    540     if (index < m_associatedElementsBeforeIndex)
    541         --m_associatedElementsBeforeIndex;
    542     if (index < m_associatedElementsAfterIndex)
    543         --m_associatedElementsAfterIndex;
    544     removeFromVector(m_associatedElements, e);
    545 }
    546 
    547 bool HTMLFormElement::isURLAttribute(const Attribute& attribute) const
    548 {
    549     return attribute.name() == actionAttr || HTMLElement::isURLAttribute(attribute);
    550 }
    551 
    552 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
    553 {
    554     ASSERT(m_imageElements.find(e) == notFound);
    555     m_imageElements.append(e);
    556 }
    557 
    558 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
    559 {
    560     ASSERT(m_imageElements.find(e) != notFound);
    561     removeFromVector(m_imageElements, e);
    562 }
    563 
    564 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
    565 {
    566     return ensureCachedHTMLCollection(FormControls);
    567 }
    568 
    569 String HTMLFormElement::name() const
    570 {
    571     return getNameAttribute();
    572 }
    573 
    574 bool HTMLFormElement::noValidate() const
    575 {
    576     return fastHasAttribute(novalidateAttr);
    577 }
    578 
    579 // FIXME: This function should be removed because it does not do the same thing as the
    580 // JavaScript binding for action, which treats action as a URL attribute. Last time I
    581 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
    582 String HTMLFormElement::action() const
    583 {
    584     return getAttribute(actionAttr);
    585 }
    586 
    587 void HTMLFormElement::setAction(const String &value)
    588 {
    589     setAttribute(actionAttr, value);
    590 }
    591 
    592 void HTMLFormElement::setEnctype(const String &value)
    593 {
    594     setAttribute(enctypeAttr, value);
    595 }
    596 
    597 String HTMLFormElement::method() const
    598 {
    599     return FormSubmission::Attributes::methodString(m_attributes.method());
    600 }
    601 
    602 void HTMLFormElement::setMethod(const String &value)
    603 {
    604     setAttribute(methodAttr, value);
    605 }
    606 
    607 String HTMLFormElement::target() const
    608 {
    609     return getAttribute(targetAttr);
    610 }
    611 
    612 bool HTMLFormElement::wasUserSubmitted() const
    613 {
    614     return m_wasUserSubmitted;
    615 }
    616 
    617 HTMLFormControlElement* HTMLFormElement::defaultButton() const
    618 {
    619     for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
    620         if (!m_associatedElements[i]->isFormControlElement())
    621             continue;
    622         HTMLFormControlElement* control = toHTMLFormControlElement(m_associatedElements[i]);
    623         if (control->isSuccessfulSubmitButton())
    624             return control;
    625     }
    626 
    627     return 0;
    628 }
    629 
    630 bool HTMLFormElement::checkValidity()
    631 {
    632     Vector<RefPtr<FormAssociatedElement> > controls;
    633     return !checkInvalidControlsAndCollectUnhandled(&controls);
    634 }
    635 
    636 bool HTMLFormElement::checkValidityWithoutDispatchingEvents()
    637 {
    638     return !checkInvalidControlsAndCollectUnhandled(0, HTMLFormControlElement::CheckValidityDispatchEventsNone);
    639 }
    640 
    641 bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls, HTMLFormControlElement::CheckValidityDispatchEvents dispatchEvents)
    642 {
    643     RefPtr<HTMLFormElement> protector(this);
    644     // Copy m_associatedElements because event handlers called from
    645     // HTMLFormControlElement::checkValidity() might change m_associatedElements.
    646     Vector<RefPtr<FormAssociatedElement> > elements;
    647     elements.reserveCapacity(m_associatedElements.size());
    648     for (unsigned i = 0; i < m_associatedElements.size(); ++i)
    649         elements.append(m_associatedElements[i]);
    650     bool hasInvalidControls = false;
    651     for (unsigned i = 0; i < elements.size(); ++i) {
    652         if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
    653             HTMLFormControlElement* control = toHTMLFormControlElement(elements[i].get());
    654             if (!control->checkValidity(unhandledInvalidControls, dispatchEvents) && control->form() == this)
    655                 hasInvalidControls = true;
    656         }
    657     }
    658     return hasInvalidControls;
    659 }
    660 
    661 Node* HTMLFormElement::elementForAlias(const AtomicString& alias)
    662 {
    663     if (alias.isEmpty() || !m_elementAliases)
    664         return 0;
    665     return m_elementAliases->get(alias.impl());
    666 }
    667 
    668 void HTMLFormElement::addElementAlias(Node* element, const AtomicString& alias)
    669 {
    670     if (alias.isEmpty())
    671         return;
    672     if (!m_elementAliases)
    673         m_elementAliases = adoptPtr(new AliasMap);
    674     m_elementAliases->set(alias.impl(), element);
    675 }
    676 
    677 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
    678 {
    679     elements()->namedItems(name, namedItems);
    680 
    681     Node* aliasElement = elementForAlias(name);
    682     if (aliasElement) {
    683         if (namedItems.find(aliasElement) == notFound) {
    684             // We have seen it before but it is gone now. Still, we need to return it.
    685             // FIXME: The above comment is not clear enough; it does not say why we need to do this.
    686             namedItems.append(aliasElement);
    687         }
    688     }
    689     if (namedItems.size() && namedItems.first() != aliasElement)
    690         addElementAlias(namedItems.first().get(), name);
    691 }
    692 
    693 bool HTMLFormElement::shouldAutocomplete() const
    694 {
    695     return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
    696 }
    697 
    698 void HTMLFormElement::finishParsingChildren()
    699 {
    700     HTMLElement::finishParsingChildren();
    701     document()->formController()->restoreControlStateIn(*this);
    702 }
    703 
    704 void HTMLFormElement::copyNonAttributePropertiesFromElement(const Element& source)
    705 {
    706     m_wasDemoted = static_cast<const HTMLFormElement&>(source).m_wasDemoted;
    707     HTMLElement::copyNonAttributePropertiesFromElement(source);
    708 }
    709 
    710 void HTMLFormElement::anonymousNamedGetter(const AtomicString& name, bool& returnValue0Enabled, RefPtr<NodeList>& returnValue0, bool& returnValue1Enabled, RefPtr<Node>& returnValue1)
    711 {
    712     // Call getNamedElements twice, first time check if it has a value
    713     // and let HTMLFormElement update its cache.
    714     // See issue: 867404
    715     {
    716         Vector<RefPtr<Node> > elements;
    717         getNamedElements(name, elements);
    718         if (elements.isEmpty())
    719             return;
    720     }
    721 
    722     // Second call may return different results from the first call,
    723     // but if the first the size cannot be zero.
    724     Vector<RefPtr<Node> > elements;
    725     getNamedElements(name, elements);
    726     ASSERT(!elements.isEmpty());
    727 
    728     if (elements.size() == 1) {
    729         returnValue1Enabled = true;
    730         returnValue1 = elements.at(0);
    731         return;
    732     }
    733 
    734     returnValue0Enabled = true;
    735     returnValue0 = NamedNodesCollection::create(elements);
    736 }
    737 
    738 void HTMLFormElement::setDemoted(bool demoted)
    739 {
    740     if (demoted)
    741         UseCounter::count(document(), UseCounter::DemotedFormElement);
    742     m_wasDemoted = demoted;
    743 }
    744 
    745 } // namespace
    746