• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
6  *           (C) 2006 Alexey Proskuryakov (ap@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 
generateFormDataIdentifier()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 
HTMLFormElement(const QualifiedName & tagName,Document * doc)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 
~HTMLFormElement()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 
formWouldHaveSecureSubmission(const String & url)103 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
104 {
105     return document()->completeURL(url).protocolIs("https");
106 }
107 
attach()108 void HTMLFormElement::attach()
109 {
110     HTMLElement::attach();
111 }
112 
rendererIsNeeded(RenderStyle * style)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 
insertedIntoDocument()138 void HTMLFormElement::insertedIntoDocument()
139 {
140     if (document()->isHTMLDocument())
141         static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
142 
143     HTMLElement::insertedIntoDocument();
144 }
145 
removedFromDocument()146 void HTMLFormElement::removedFromDocument()
147 {
148     if (document()->isHTMLDocument())
149         static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
150 
151     HTMLElement::removedFromDocument();
152 }
153 
handleLocalEvents(Event * event)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 
length() const164 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 
item(unsigned index)174 Node* HTMLFormElement::item(unsigned index)
175 {
176     return elements()->item(index);
177 }
178 
submitClick(Event * event)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 
dataEncoding() const196 TextEncoding HTMLFormElement::dataEncoding() const
197 {
198     if (isMailtoForm())
199         return UTF8Encoding();
200 
201     return m_formDataBuilder.dataEncoding(document());
202 }
203 
createFormData(const CString & boundary)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 
isMailtoForm() const286 bool HTMLFormElement::isMailtoForm() const
287 {
288     return protocolIs(m_url, "mailto");
289 }
290 
prepareSubmit(Event * event)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 
transferMailtoPostFormDataToURL(RefPtr<FormData> & data,KURL & url,const String & encodingType)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 
submit(Frame * javaScriptActiveFrame)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 
submit(Event * event,bool activateSubmitButton,bool lockHistory,FormSubmissionTrigger formSubmissionTrigger)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 
reset()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 
parseMappedAttribute(MappedAttribute * attr)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 
removeFromVector(Vector<T *,n> & vec,T * item)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 
formElementIndex(HTMLFormControlElement * e)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 
registerFormElement(HTMLFormControlElement * e)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 
removeFormElement(HTMLFormControlElement * e)514 void HTMLFormElement::removeFormElement(HTMLFormControlElement* e)
515 {
516     m_checkedRadioButtons.removeButton(e);
517     removeFromVector(formElements, e);
518 }
519 
isURLAttribute(Attribute * attr) const520 bool HTMLFormElement::isURLAttribute(Attribute* attr) const
521 {
522     return attr->name() == actionAttr;
523 }
524 
registerImgElement(HTMLImageElement * e)525 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
526 {
527     ASSERT(imgElements.find(e) == notFound);
528     imgElements.append(e);
529 }
530 
removeImgElement(HTMLImageElement * e)531 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
532 {
533     ASSERT(imgElements.find(e) != notFound);
534     removeFromVector(imgElements, e);
535 }
536 
elements()537 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
538 {
539     return HTMLFormCollection::create(this);
540 }
541 
name() const542 String HTMLFormElement::name() const
543 {
544     return getAttribute(nameAttr);
545 }
546 
setName(const String & value)547 void HTMLFormElement::setName(const String &value)
548 {
549     setAttribute(nameAttr, value);
550 }
551 
noValidate() const552 bool HTMLFormElement::noValidate() const
553 {
554     return !getAttribute(novalidateAttr).isNull();
555 }
556 
setNoValidate(bool novalidate)557 void HTMLFormElement::setNoValidate(bool novalidate)
558 {
559     setAttribute(novalidateAttr, novalidate ? "" : 0);
560 }
561 
setAcceptCharset(const String & value)562 void HTMLFormElement::setAcceptCharset(const String &value)
563 {
564     setAttribute(accept_charsetAttr, value);
565 }
566 
action() const567 String HTMLFormElement::action() const
568 {
569     return getAttribute(actionAttr);
570 }
571 
setAction(const String & value)572 void HTMLFormElement::setAction(const String &value)
573 {
574     setAttribute(actionAttr, value);
575 }
576 
setEnctype(const String & value)577 void HTMLFormElement::setEnctype(const String &value)
578 {
579     setAttribute(enctypeAttr, value);
580 }
581 
method() const582 String HTMLFormElement::method() const
583 {
584     return getAttribute(methodAttr);
585 }
586 
setMethod(const String & value)587 void HTMLFormElement::setMethod(const String &value)
588 {
589     setAttribute(methodAttr, value);
590 }
591 
target() const592 String HTMLFormElement::target() const
593 {
594     return getAttribute(targetAttr);
595 }
596 
setTarget(const String & value)597 void HTMLFormElement::setTarget(const String &value)
598 {
599     setAttribute(targetAttr, value);
600 }
601 
defaultButton() const602 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 
checkValidity()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 
elementForAlias(const AtomicString & alias)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 
addElementAlias(HTMLFormControlElement * element,const AtomicString & alias)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 
getNamedElements(const AtomicString & name,Vector<RefPtr<Node>> & namedItems)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 
documentDidBecomeActive()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 
willMoveToNewOwnerDocument()674 void HTMLFormElement::willMoveToNewOwnerDocument()
675 {
676     if (!m_autocomplete)
677         document()->unregisterForDocumentActivationCallbacks(this);
678     HTMLElement::willMoveToNewOwnerDocument();
679 }
680 
didMoveToNewOwnerDocument()681 void HTMLFormElement::didMoveToNewOwnerDocument()
682 {
683     if (!m_autocomplete)
684         document()->registerForDocumentActivationCallbacks(this);
685     HTMLElement::didMoveToNewOwnerDocument();
686 }
687 
688 } // namespace
689