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 "HTMLFormElement.h"
     27 
     28 #include "CSSHelper.h"
     29 #include "Chrome.h"
     30 #include "ChromeClient.h"
     31 #include "Document.h"
     32 #include "Event.h"
     33 #include "EventNames.h"
     34 #include "FileList.h"
     35 #include "FileSystem.h"
     36 #include "FormData.h"
     37 #include "FormDataList.h"
     38 #include "FormState.h"
     39 #include "Frame.h"
     40 #include "FrameLoader.h"
     41 #include "HTMLDocument.h"
     42 #include "HTMLFormCollection.h"
     43 #include "HTMLImageElement.h"
     44 #include "HTMLInputElement.h"
     45 #include "HTMLNames.h"
     46 #include "ScriptEventListener.h"
     47 #include "MIMETypeRegistry.h"
     48 #include "MappedAttribute.h"
     49 #include "Page.h"
     50 #include "RenderTextControl.h"
     51 #include "ValidityState.h"
     52 #include <limits>
     53 #include <wtf/CurrentTime.h>
     54 #include <wtf/RandomNumber.h>
     55 
     56 #if PLATFORM(WX)
     57 #include <wx/defs.h>
     58 #include <wx/filename.h>
     59 #endif
     60 
     61 using namespace std;
     62 
     63 namespace WebCore {
     64 
     65 using namespace HTMLNames;
     66 
     67 static int64_t generateFormDataIdentifier()
     68 {
     69     // Initialize to the current time to reduce the likelihood of generating
     70     // identifiers that overlap with those from past/future browser sessions.
     71     static int64_t nextIdentifier = static_cast<int64_t>(currentTime() * 1000000.0);
     72     return ++nextIdentifier;
     73 }
     74 
     75 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* doc)
     76     : HTMLElement(tagName, doc)
     77     , m_elementAliases(0)
     78     , collectionInfo(0)
     79     , m_autocomplete(true)
     80     , m_insubmit(false)
     81     , m_doingsubmit(false)
     82     , m_inreset(false)
     83     , m_malformed(false)
     84     , m_demoted(false)
     85 {
     86     ASSERT(hasTagName(formTag));
     87 }
     88 
     89 HTMLFormElement::~HTMLFormElement()
     90 {
     91     if (!m_autocomplete)
     92         document()->unregisterForDocumentActivationCallbacks(this);
     93 
     94     delete m_elementAliases;
     95     delete collectionInfo;
     96 
     97     for (unsigned i = 0; i < formElements.size(); ++i)
     98         formElements[i]->formDestroyed();
     99     for (unsigned i = 0; i < imgElements.size(); ++i)
    100         imgElements[i]->m_form = 0;
    101 }
    102 
    103 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
    104 {
    105     return document()->completeURL(url).protocolIs("https");
    106 }
    107 
    108 void HTMLFormElement::attach()
    109 {
    110     HTMLElement::attach();
    111 }
    112 
    113 bool HTMLFormElement::rendererIsNeeded(RenderStyle* style)
    114 {
    115     if (!isDemoted())
    116         return HTMLElement::rendererIsNeeded(style);
    117 
    118     Node* node = parentNode();
    119     RenderObject* parentRenderer = node->renderer();
    120     bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
    121         || (parentRenderer->isTableRow() && node->hasTagName(trTag))
    122         || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
    123         || (parentRenderer->isTableCol() && node->hasTagName(colTag))
    124         || (parentRenderer->isTableCell() && node->hasTagName(trTag));
    125 
    126     if (!parentIsTableElementPart)
    127         return true;
    128 
    129     EDisplay display = style->display();
    130     bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
    131         || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
    132         || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
    133         || display == TABLE_CAPTION;
    134 
    135     return formIsTablePart;
    136 }
    137 
    138 void HTMLFormElement::insertedIntoDocument()
    139 {
    140     if (document()->isHTMLDocument())
    141         static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
    142 
    143     HTMLElement::insertedIntoDocument();
    144 }
    145 
    146 void HTMLFormElement::removedFromDocument()
    147 {
    148     if (document()->isHTMLDocument())
    149         static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
    150 
    151     HTMLElement::removedFromDocument();
    152 }
    153 
    154 void HTMLFormElement::handleLocalEvents(Event* event)
    155 {
    156     Node* targetNode = event->target()->toNode();
    157     if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
    158         event->stopPropagation();
    159         return;
    160     }
    161     HTMLElement::handleLocalEvents(event);
    162 }
    163 
    164 unsigned HTMLFormElement::length() const
    165 {
    166     int len = 0;
    167     for (unsigned i = 0; i < formElements.size(); ++i)
    168         if (formElements[i]->isEnumeratable())
    169             ++len;
    170 
    171     return len;
    172 }
    173 
    174 Node* HTMLFormElement::item(unsigned index)
    175 {
    176     return elements()->item(index);
    177 }
    178 
    179 void HTMLFormElement::submitClick(Event* event)
    180 {
    181     bool submitFound = false;
    182     for (unsigned i = 0; i < formElements.size(); ++i) {
    183         if (formElements[i]->hasLocalName(inputTag)) {
    184             HTMLInputElement* element = static_cast<HTMLInputElement*>(formElements[i]);
    185             if (element->isSuccessfulSubmitButton() && element->renderer()) {
    186                 submitFound = true;
    187                 element->dispatchSimulatedClick(event);
    188                 break;
    189             }
    190         }
    191     }
    192     if (!submitFound) // submit the form without a submit or image input
    193         prepareSubmit(event);
    194 }
    195 
    196 TextEncoding HTMLFormElement::dataEncoding() const
    197 {
    198     if (isMailtoForm())
    199         return UTF8Encoding();
    200 
    201     return m_formDataBuilder.dataEncoding(document());
    202 }
    203 
    204 PassRefPtr<FormData> HTMLFormElement::createFormData(const CString& boundary)
    205 {
    206     Vector<char> encodedData;
    207     TextEncoding encoding = dataEncoding().encodingForFormSubmission();
    208 
    209     RefPtr<FormData> result = FormData::create();
    210 
    211     for (unsigned i = 0; i < formElements.size(); ++i) {
    212         HTMLFormControlElement* control = formElements[i];
    213         FormDataList list(encoding);
    214 
    215         if (!control->disabled() && control->appendFormData(list, m_formDataBuilder.isMultiPartForm())) {
    216             size_t formDataListSize = list.list().size();
    217             ASSERT(formDataListSize % 2 == 0);
    218             for (size_t j = 0; j < formDataListSize; j += 2) {
    219                 const FormDataList::Item& key = list.list()[j];
    220                 const FormDataList::Item& value = list.list()[j + 1];
    221                 if (!m_formDataBuilder.isMultiPartForm()) {
    222                     // Omit the name "isindex" if it's the first form data element.
    223                     // FIXME: Why is this a good rule? Is this obsolete now?
    224                     if (encodedData.isEmpty() && key.data() == "isindex")
    225                         FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
    226                     else
    227                         m_formDataBuilder.addKeyValuePairAsFormData(encodedData, key.data(), value.data());
    228                 } else {
    229                     Vector<char> header;
    230                     m_formDataBuilder.beginMultiPartHeader(header, boundary, key.data());
    231 
    232                     bool shouldGenerateFile = false;
    233                     // if the current type is FILE, then we also need to include the filename
    234                     if (value.file()) {
    235                         const String& path = value.file()->path();
    236                         String fileName = value.file()->fileName();
    237 
    238                         // Let the application specify a filename if it's going to generate a replacement file for the upload.
    239                         if (!path.isEmpty()) {
    240                             if (Page* page = document()->page()) {
    241                                 String generatedFileName;
    242                                 shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
    243                                 if (shouldGenerateFile)
    244                                     fileName = generatedFileName;
    245                             }
    246                         }
    247 
    248                         // We have to include the filename=".." part in the header, even if the filename is empty
    249                         m_formDataBuilder.addFilenameToMultiPartHeader(header, encoding, fileName);
    250 
    251                         if (!fileName.isEmpty()) {
    252                             // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path,
    253                             // not just a basename. But filename is not the path. But note that it's not safe to
    254                             // just use path instead since in the generated-file case it will not reflect the
    255                             // MIME type of the generated file.
    256                             String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName);
    257                             if (!mimeType.isEmpty())
    258                                 m_formDataBuilder.addContentTypeToMultiPartHeader(header, mimeType.latin1());
    259                         }
    260                     }
    261 
    262                     m_formDataBuilder.finishMultiPartHeader(header);
    263 
    264                     // Append body
    265                     result->appendData(header.data(), header.size());
    266                     if (size_t dataSize = value.data().length())
    267                         result->appendData(value.data().data(), dataSize);
    268                     else if (value.file() && !value.file()->path().isEmpty())
    269                         result->appendFile(value.file()->path(), shouldGenerateFile);
    270 
    271                     result->appendData("\r\n", 2);
    272                 }
    273             }
    274         }
    275     }
    276 
    277     if (m_formDataBuilder.isMultiPartForm())
    278         m_formDataBuilder.addBoundaryToMultiPartHeader(encodedData, boundary, true);
    279 
    280     result->appendData(encodedData.data(), encodedData.size());
    281 
    282     result->setIdentifier(generateFormDataIdentifier());
    283     return result;
    284 }
    285 
    286 bool HTMLFormElement::isMailtoForm() const
    287 {
    288     return protocolIs(m_url, "mailto");
    289 }
    290 
    291 bool HTMLFormElement::prepareSubmit(Event* event)
    292 {
    293     Frame* frame = document()->frame();
    294     if (m_insubmit || !frame)
    295         return m_insubmit;
    296 
    297     m_insubmit = true;
    298     m_doingsubmit = false;
    299 
    300     if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
    301         m_doingsubmit = true;
    302 
    303     m_insubmit = false;
    304 
    305     if (m_doingsubmit)
    306         submit(event, true, false, NotSubmittedByJavaScript);
    307 
    308     return m_doingsubmit;
    309 }
    310 
    311 static void transferMailtoPostFormDataToURL(RefPtr<FormData>& data, KURL& url, const String& encodingType)
    312 {
    313     String body = data->flattenToString();
    314     data = FormData::create();
    315 
    316     if (equalIgnoringCase(encodingType, "text/plain")) {
    317         // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20.
    318         body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n");
    319     }
    320 
    321     Vector<char> bodyData;
    322     bodyData.append("body=", 5);
    323     FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8());
    324     body = String(bodyData.data(), bodyData.size()).replace('+', "%20");
    325 
    326     String query = url.query();
    327     if (!query.isEmpty())
    328         query.append('&');
    329     query.append(body);
    330     url.setQuery(query);
    331 }
    332 
    333 void HTMLFormElement::submit(Frame* javaScriptActiveFrame)
    334 {
    335     if (javaScriptActiveFrame)
    336         submit(0, false, !javaScriptActiveFrame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
    337     else
    338         submit(0, false, false, NotSubmittedByJavaScript);
    339 }
    340 
    341 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockHistory, FormSubmissionTrigger formSubmissionTrigger)
    342 {
    343     FrameView* view = document()->view();
    344     Frame* frame = document()->frame();
    345     if (!view || !frame)
    346         return;
    347 
    348     if (m_insubmit) {
    349         m_doingsubmit = true;
    350         return;
    351     }
    352 
    353     m_insubmit = true;
    354 
    355     HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
    356     bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
    357 
    358     Vector<pair<String, String> > formValues;
    359 
    360     for (unsigned i = 0; i < formElements.size(); ++i) {
    361         HTMLFormControlElement* control = formElements[i];
    362         if (control->hasLocalName(inputTag)) {
    363             HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
    364             if (input->isTextField()) {
    365                 formValues.append(pair<String, String>(input->name(), input->value()));
    366                 if (input->isSearchField())
    367                     input->addSearchResult();
    368             }
    369         }
    370         if (needButtonActivation) {
    371             if (control->isActivatedSubmit())
    372                 needButtonActivation = false;
    373             else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
    374                 firstSuccessfulSubmitButton = control;
    375         }
    376     }
    377 
    378     RefPtr<FormState> formState = FormState::create(this, formValues, frame, formSubmissionTrigger);
    379 
    380     if (needButtonActivation && firstSuccessfulSubmitButton)
    381         firstSuccessfulSubmitButton->setActivatedSubmit(true);
    382 
    383     if (m_url.isEmpty())
    384         m_url = document()->url().string();
    385 
    386     if (m_formDataBuilder.isPostMethod()) {
    387         if (m_formDataBuilder.isMultiPartForm() && isMailtoForm()) {
    388             setEnctype("application/x-www-form-urlencoded");
    389             ASSERT(!m_formDataBuilder.isMultiPartForm());
    390         }
    391 
    392         if (!m_formDataBuilder.isMultiPartForm()) {
    393             RefPtr<FormData> data = createFormData(CString());
    394 
    395             if (isMailtoForm()) {
    396                 // Convert the form data into a string that we put into the URL.
    397                 KURL url = document()->completeURL(m_url);
    398                 transferMailtoPostFormDataToURL(data, url, m_formDataBuilder.encodingType());
    399                 m_url = url.string();
    400             }
    401 
    402             frame->loader()->submitForm("POST", m_url, data.release(), m_target, m_formDataBuilder.encodingType(), String(), lockHistory, event, formState.release());
    403         } else {
    404             Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString();
    405             frame->loader()->submitForm("POST", m_url, createFormData(boundary.data()), m_target, m_formDataBuilder.encodingType(), boundary.data(), lockHistory, event, formState.release());
    406         }
    407     } else {
    408         m_formDataBuilder.setIsMultiPartForm(false);
    409         frame->loader()->submitForm("GET", m_url, createFormData(CString()), m_target, String(), String(), lockHistory, event, formState.release());
    410     }
    411 
    412     if (needButtonActivation && firstSuccessfulSubmitButton)
    413         firstSuccessfulSubmitButton->setActivatedSubmit(false);
    414 
    415     m_doingsubmit = m_insubmit = false;
    416 }
    417 
    418 void HTMLFormElement::reset()
    419 {
    420     Frame* frame = document()->frame();
    421     if (m_inreset || !frame)
    422         return;
    423 
    424     m_inreset = true;
    425 
    426     // ### DOM2 labels this event as not cancelable, however
    427     // common browsers( sick! ) allow it be cancelled.
    428     if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
    429         m_inreset = false;
    430         return;
    431     }
    432 
    433     for (unsigned i = 0; i < formElements.size(); ++i)
    434         formElements[i]->reset();
    435 
    436     m_inreset = false;
    437 }
    438 
    439 void HTMLFormElement::parseMappedAttribute(MappedAttribute* attr)
    440 {
    441     if (attr->name() == actionAttr)
    442         m_url = deprecatedParseURL(attr->value());
    443     else if (attr->name() == targetAttr)
    444         m_target = attr->value();
    445     else if (attr->name() == methodAttr)
    446         m_formDataBuilder.parseMethodType(attr->value());
    447     else if (attr->name() == enctypeAttr)
    448         m_formDataBuilder.parseEncodingType(attr->value());
    449     else if (attr->name() == accept_charsetAttr)
    450         // space separated list of charsets the server
    451         // accepts - see rfc2045
    452         m_formDataBuilder.setAcceptCharset(attr->value());
    453     else if (attr->name() == acceptAttr) {
    454         // ignore this one for the moment...
    455     } else if (attr->name() == autocompleteAttr) {
    456         m_autocomplete = !equalIgnoringCase(attr->value(), "off");
    457         if (!m_autocomplete)
    458             document()->registerForDocumentActivationCallbacks(this);
    459         else
    460             document()->unregisterForDocumentActivationCallbacks(this);
    461     } else if (attr->name() == onsubmitAttr)
    462         setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr));
    463     else if (attr->name() == onresetAttr)
    464         setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr));
    465     else if (attr->name() == nameAttr) {
    466         const AtomicString& newName = attr->value();
    467         if (inDocument() && document()->isHTMLDocument()) {
    468             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
    469             document->removeNamedItem(m_name);
    470             document->addNamedItem(newName);
    471         }
    472         m_name = newName;
    473     } else
    474         HTMLElement::parseMappedAttribute(attr);
    475 }
    476 
    477 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
    478 {
    479     size_t size = vec.size();
    480     for (size_t i = 0; i != size; ++i)
    481         if (vec[i] == item) {
    482             vec.remove(i);
    483             break;
    484         }
    485 }
    486 
    487 unsigned HTMLFormElement::formElementIndex(HTMLFormControlElement* e)
    488 {
    489     // Check for the special case where this element is the very last thing in
    490     // the form's tree of children; we don't want to walk the entire tree in that
    491     // common case that occurs during parsing; instead we'll just return a value
    492     // that says "add this form element to the end of the array".
    493     if (e->traverseNextNode(this)) {
    494         unsigned i = 0;
    495         for (Node* node = this; node; node = node->traverseNextNode(this)) {
    496             if (node == e)
    497                 return i;
    498             if (node->isHTMLElement()
    499                     && static_cast<Element*>(node)->isFormControlElement()
    500                     && static_cast<HTMLFormControlElement*>(node)->form() == this)
    501                 ++i;
    502         }
    503     }
    504     return formElements.size();
    505 }
    506 
    507 void HTMLFormElement::registerFormElement(HTMLFormControlElement* e)
    508 {
    509     document()->checkedRadioButtons().removeButton(e);
    510     m_checkedRadioButtons.addButton(e);
    511     formElements.insert(formElementIndex(e), e);
    512 }
    513 
    514 void HTMLFormElement::removeFormElement(HTMLFormControlElement* e)
    515 {
    516     m_checkedRadioButtons.removeButton(e);
    517     removeFromVector(formElements, e);
    518 }
    519 
    520 bool HTMLFormElement::isURLAttribute(Attribute* attr) const
    521 {
    522     return attr->name() == actionAttr;
    523 }
    524 
    525 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
    526 {
    527     ASSERT(imgElements.find(e) == notFound);
    528     imgElements.append(e);
    529 }
    530 
    531 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
    532 {
    533     ASSERT(imgElements.find(e) != notFound);
    534     removeFromVector(imgElements, e);
    535 }
    536 
    537 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
    538 {
    539     return HTMLFormCollection::create(this);
    540 }
    541 
    542 String HTMLFormElement::name() const
    543 {
    544     return getAttribute(nameAttr);
    545 }
    546 
    547 void HTMLFormElement::setName(const String &value)
    548 {
    549     setAttribute(nameAttr, value);
    550 }
    551 
    552 bool HTMLFormElement::noValidate() const
    553 {
    554     return !getAttribute(novalidateAttr).isNull();
    555 }
    556 
    557 void HTMLFormElement::setNoValidate(bool novalidate)
    558 {
    559     setAttribute(novalidateAttr, novalidate ? "" : 0);
    560 }
    561 
    562 void HTMLFormElement::setAcceptCharset(const String &value)
    563 {
    564     setAttribute(accept_charsetAttr, value);
    565 }
    566 
    567 String HTMLFormElement::action() const
    568 {
    569     return getAttribute(actionAttr);
    570 }
    571 
    572 void HTMLFormElement::setAction(const String &value)
    573 {
    574     setAttribute(actionAttr, value);
    575 }
    576 
    577 void HTMLFormElement::setEnctype(const String &value)
    578 {
    579     setAttribute(enctypeAttr, value);
    580 }
    581 
    582 String HTMLFormElement::method() const
    583 {
    584     return getAttribute(methodAttr);
    585 }
    586 
    587 void HTMLFormElement::setMethod(const String &value)
    588 {
    589     setAttribute(methodAttr, value);
    590 }
    591 
    592 String HTMLFormElement::target() const
    593 {
    594     return getAttribute(targetAttr);
    595 }
    596 
    597 void HTMLFormElement::setTarget(const String &value)
    598 {
    599     setAttribute(targetAttr, value);
    600 }
    601 
    602 HTMLFormControlElement* HTMLFormElement::defaultButton() const
    603 {
    604     for (unsigned i = 0; i < formElements.size(); ++i) {
    605         HTMLFormControlElement* control = formElements[i];
    606         if (control->isSuccessfulSubmitButton())
    607             return control;
    608     }
    609 
    610     return 0;
    611 }
    612 
    613 bool HTMLFormElement::checkValidity()
    614 {
    615     // TODO: Check for unhandled invalid controls, see #27452 for tips.
    616 
    617     bool hasOnlyValidControls = true;
    618     for (unsigned i = 0; i < formElements.size(); ++i) {
    619         HTMLFormControlElement* control = formElements[i];
    620         if (!control->checkValidity())
    621             hasOnlyValidControls = false;
    622     }
    623 
    624     return hasOnlyValidControls;
    625 }
    626 
    627 PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias)
    628 {
    629     if (alias.isEmpty() || !m_elementAliases)
    630         return 0;
    631     return m_elementAliases->get(alias.impl());
    632 }
    633 
    634 void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
    635 {
    636     if (alias.isEmpty())
    637         return;
    638     if (!m_elementAliases)
    639         m_elementAliases = new AliasMap;
    640     m_elementAliases->set(alias.impl(), element);
    641 }
    642 
    643 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
    644 {
    645     elements()->namedItems(name, namedItems);
    646 
    647     // see if we have seen something with this name before
    648     RefPtr<HTMLFormControlElement> aliasElem;
    649     if (aliasElem = elementForAlias(name)) {
    650         bool found = false;
    651         for (unsigned n = 0; n < namedItems.size(); n++) {
    652             if (namedItems[n] == aliasElem.get()) {
    653                 found = true;
    654                 break;
    655             }
    656         }
    657         if (!found)
    658             // we have seen it before but it is gone now. still, we need to return it.
    659             namedItems.append(aliasElem.get());
    660     }
    661     // name has been accessed, remember it
    662     if (namedItems.size() && aliasElem != namedItems.first())
    663         addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
    664 }
    665 
    666 void HTMLFormElement::documentDidBecomeActive()
    667 {
    668     ASSERT(!m_autocomplete);
    669 
    670     for (unsigned i = 0; i < formElements.size(); ++i)
    671         formElements[i]->reset();
    672 }
    673 
    674 void HTMLFormElement::willMoveToNewOwnerDocument()
    675 {
    676     if (!m_autocomplete)
    677         document()->unregisterForDocumentActivationCallbacks(this);
    678     HTMLElement::willMoveToNewOwnerDocument();
    679 }
    680 
    681 void HTMLFormElement::didMoveToNewOwnerDocument()
    682 {
    683     if (!m_autocomplete)
    684         document()->registerForDocumentActivationCallbacks(this);
    685     HTMLElement::didMoveToNewOwnerDocument();
    686 }
    687 
    688 } // namespace
    689