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