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 "Attribute.h"
29 #include "DOMFormData.h"
30 #include "DOMWindow.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 "FrameLoaderClient.h"
42 #include "HTMLDocument.h"
43 #include "HTMLFormCollection.h"
44 #include "HTMLImageElement.h"
45 #include "HTMLInputElement.h"
46 #include "HTMLNames.h"
47 #include "MIMETypeRegistry.h"
48 #include "Page.h"
49 #include "RenderTextControl.h"
50 #include "ScriptEventListener.h"
51 #include "Settings.h"
52 #include "ValidityState.h"
53 #include <limits>
54
55 #if PLATFORM(WX)
56 #include <wx/defs.h>
57 #include <wx/filename.h>
58 #endif
59
60 using namespace std;
61
62 namespace WebCore {
63
64 using namespace HTMLNames;
65
HTMLFormElement(const QualifiedName & tagName,Document * document)66 HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* document)
67 : HTMLElement(tagName, document)
68 , m_associatedElementsBeforeIndex(0)
69 , m_associatedElementsAfterIndex(0)
70 , m_wasUserSubmitted(false)
71 , m_isSubmittingOrPreparingForSubmission(false)
72 , m_shouldSubmit(false)
73 , m_isInResetFunction(false)
74 , m_wasMalformed(false)
75 , m_wasDemoted(false)
76 {
77 ASSERT(hasTagName(formTag));
78 }
79
create(Document * document)80 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
81 {
82 return adoptRef(new HTMLFormElement(formTag, document));
83 }
84
create(const QualifiedName & tagName,Document * document)85 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
86 {
87 return adoptRef(new HTMLFormElement(tagName, document));
88 }
89
~HTMLFormElement()90 HTMLFormElement::~HTMLFormElement()
91 {
92 if (!autoComplete())
93 document()->unregisterForDocumentActivationCallbacks(this);
94
95 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
96 m_associatedElements[i]->formDestroyed();
97 for (unsigned i = 0; i < m_imageElements.size(); ++i)
98 m_imageElements[i]->m_form = 0;
99 }
100
formWouldHaveSecureSubmission(const String & url)101 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
102 {
103 return document()->completeURL(url).protocolIs("https");
104 }
105
rendererIsNeeded(RenderStyle * style)106 bool HTMLFormElement::rendererIsNeeded(RenderStyle* style)
107 {
108 if (!m_wasDemoted)
109 return HTMLElement::rendererIsNeeded(style);
110
111 ContainerNode* node = parentNode();
112 RenderObject* parentRenderer = node->renderer();
113 bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag))
114 || (parentRenderer->isTableRow() && node->hasTagName(trTag))
115 || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag))
116 || (parentRenderer->isTableCol() && node->hasTagName(colTag))
117 || (parentRenderer->isTableCell() && node->hasTagName(trTag));
118
119 if (!parentIsTableElementPart)
120 return true;
121
122 EDisplay display = style->display();
123 bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP
124 || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW
125 || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL
126 || display == TABLE_CAPTION;
127
128 return formIsTablePart;
129 }
130
insertedIntoDocument()131 void HTMLFormElement::insertedIntoDocument()
132 {
133 if (document()->isHTMLDocument())
134 static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
135
136 HTMLElement::insertedIntoDocument();
137
138 if (hasID())
139 document()->resetFormElementsOwner(this);
140 }
141
removedFromDocument()142 void HTMLFormElement::removedFromDocument()
143 {
144 if (document()->isHTMLDocument())
145 static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
146
147 HTMLElement::removedFromDocument();
148
149 if (hasID())
150 document()->resetFormElementsOwner(0);
151 }
152
handleLocalEvents(Event * event)153 void HTMLFormElement::handleLocalEvents(Event* event)
154 {
155 Node* targetNode = event->target()->toNode();
156 if (event->eventPhase() != Event::CAPTURING_PHASE && targetNode && targetNode != this && (event->type() == eventNames().submitEvent || event->type() == eventNames().resetEvent)) {
157 event->stopPropagation();
158 return;
159 }
160 HTMLElement::handleLocalEvents(event);
161 }
162
length() const163 unsigned HTMLFormElement::length() const
164 {
165 unsigned len = 0;
166 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
167 if (m_associatedElements[i]->isEnumeratable())
168 ++len;
169 return len;
170 }
171
item(unsigned index)172 Node* HTMLFormElement::item(unsigned index)
173 {
174 return elements()->item(index);
175 }
176
submitImplicitly(Event * event,bool fromImplicitSubmissionTrigger)177 void HTMLFormElement::submitImplicitly(Event* event, bool fromImplicitSubmissionTrigger)
178 {
179 int submissionTriggerCount = 0;
180 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
181 FormAssociatedElement* formAssociatedElement = m_associatedElements[i];
182 if (!formAssociatedElement->isFormControlElement())
183 continue;
184 HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(formAssociatedElement);
185 if (formElement->isSuccessfulSubmitButton()) {
186 if (formElement->renderer()) {
187 formElement->dispatchSimulatedClick(event);
188 return;
189 }
190 } else if (formElement->canTriggerImplicitSubmission())
191 ++submissionTriggerCount;
192 }
193 if (fromImplicitSubmissionTrigger && submissionTriggerCount == 1)
194 prepareForSubmission(event);
195 }
196
submitElementFromEvent(const Event * event)197 static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
198 {
199 Node* targetNode = event->target()->toNode();
200 if (!targetNode || !targetNode->isElementNode())
201 return 0;
202 Element* targetElement = static_cast<Element*>(targetNode);
203 if (!targetElement->isFormControlElement())
204 return 0;
205 return static_cast<HTMLFormControlElement*>(targetElement);
206 }
207
validateInteractively(Event * event)208 bool HTMLFormElement::validateInteractively(Event* event)
209 {
210 ASSERT(event);
211 if (!document()->page() || !document()->page()->settings()->interactiveFormValidationEnabled() || noValidate())
212 return true;
213
214 HTMLFormControlElement* submitElement = submitElementFromEvent(event);
215 if (submitElement && submitElement->formNoValidate())
216 return true;
217
218 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
219 if (m_associatedElements[i]->isFormControlElement())
220 static_cast<HTMLFormControlElement*>(m_associatedElements[i])->hideVisibleValidationMessage();
221 }
222
223 Vector<RefPtr<FormAssociatedElement> > unhandledInvalidControls;
224 if (!checkInvalidControlsAndCollectUnhandled(unhandledInvalidControls))
225 return true;
226 // Because the form has invalid controls, we abort the form submission and
227 // show a validation message on a focusable form control.
228
229 // Needs to update layout now because we'd like to call isFocusable(), which
230 // has !renderer()->needsLayout() assertion.
231 document()->updateLayoutIgnorePendingStylesheets();
232
233 RefPtr<HTMLFormElement> protector(this);
234 // Focus on the first focusable control and show a validation message.
235 for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
236 FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
237 HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
238 if (unhandled->isFocusable() && unhandled->inDocument()) {
239 unhandled->scrollIntoViewIfNeeded(false);
240 unhandled->focus();
241 if (unhandled->isFormControlElement())
242 static_cast<HTMLFormControlElement*>(unhandled)->updateVisibleValidationMessage();
243 break;
244 }
245 }
246 // Warn about all of unfocusable controls.
247 if (Frame* frame = document()->frame()) {
248 for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
249 FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
250 HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
251 if (unhandled->isFocusable() && unhandled->inDocument())
252 continue;
253 String message("An invalid form control with name='%name' is not focusable.");
254 message.replace("%name", unhandledAssociatedElement->name());
255 frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string());
256 }
257 }
258 return false;
259 }
260
prepareForSubmission(Event * event)261 bool HTMLFormElement::prepareForSubmission(Event* event)
262 {
263 Frame* frame = document()->frame();
264 if (m_isSubmittingOrPreparingForSubmission || !frame)
265 return m_isSubmittingOrPreparingForSubmission;
266
267 m_isSubmittingOrPreparingForSubmission = true;
268 m_shouldSubmit = false;
269
270 // Interactive validation must be done before dispatching the submit event.
271 if (!validateInteractively(event)) {
272 m_isSubmittingOrPreparingForSubmission = false;
273 return false;
274 }
275
276 frame->loader()->client()->dispatchWillSendSubmitEvent(this);
277
278 if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
279 m_shouldSubmit = true;
280
281 m_isSubmittingOrPreparingForSubmission = false;
282
283 if (m_shouldSubmit)
284 submit(event, true, true, NotSubmittedByJavaScript);
285
286 return m_shouldSubmit;
287 }
288
submit()289 void HTMLFormElement::submit()
290 {
291 submit(0, false, true, NotSubmittedByJavaScript);
292 }
293
submitFromJavaScript()294 void HTMLFormElement::submitFromJavaScript()
295 {
296 Frame* frame = document()->frame();
297 if (!frame)
298 return;
299 submit(0, false, frame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
300 }
301
submit(Event * event,bool activateSubmitButton,bool processingUserGesture,FormSubmissionTrigger formSubmissionTrigger)302 void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
303 {
304 FrameView* view = document()->view();
305 Frame* frame = document()->frame();
306 if (!view || !frame)
307 return;
308
309 if (m_isSubmittingOrPreparingForSubmission) {
310 m_shouldSubmit = true;
311 return;
312 }
313
314 m_isSubmittingOrPreparingForSubmission = true;
315 m_wasUserSubmitted = processingUserGesture;
316
317 HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
318 bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
319
320 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
321 FormAssociatedElement* associatedElement = m_associatedElements[i];
322 if (!associatedElement->isFormControlElement())
323 continue;
324 if (needButtonActivation) {
325 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(associatedElement);
326 if (control->isActivatedSubmit())
327 needButtonActivation = false;
328 else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
329 firstSuccessfulSubmitButton = control;
330 }
331 }
332
333 if (needButtonActivation && firstSuccessfulSubmitButton)
334 firstSuccessfulSubmitButton->setActivatedSubmit(true);
335
336 frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, !processingUserGesture, formSubmissionTrigger));
337
338 if (needButtonActivation && firstSuccessfulSubmitButton)
339 firstSuccessfulSubmitButton->setActivatedSubmit(false);
340
341 m_shouldSubmit = false;
342 m_isSubmittingOrPreparingForSubmission = false;
343 }
344
reset()345 void HTMLFormElement::reset()
346 {
347 Frame* frame = document()->frame();
348 if (m_isInResetFunction || !frame)
349 return;
350
351 m_isInResetFunction = true;
352
353 if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
354 m_isInResetFunction = false;
355 return;
356 }
357
358 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
359 if (m_associatedElements[i]->isFormControlElement())
360 static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
361 }
362
363 m_isInResetFunction = false;
364 }
365
parseMappedAttribute(Attribute * attr)366 void HTMLFormElement::parseMappedAttribute(Attribute* attr)
367 {
368 if (attr->name() == actionAttr)
369 m_attributes.parseAction(attr->value());
370 else if (attr->name() == targetAttr)
371 m_attributes.setTarget(attr->value());
372 else if (attr->name() == methodAttr)
373 m_attributes.parseMethodType(attr->value());
374 else if (attr->name() == enctypeAttr)
375 m_attributes.parseEncodingType(attr->value());
376 else if (attr->name() == accept_charsetAttr)
377 m_attributes.setAcceptCharset(attr->value());
378 else if (attr->name() == autocompleteAttr) {
379 if (!autoComplete())
380 document()->registerForDocumentActivationCallbacks(this);
381 else
382 document()->unregisterForDocumentActivationCallbacks(this);
383 } else if (attr->name() == onsubmitAttr)
384 setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr));
385 else if (attr->name() == onresetAttr)
386 setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr));
387 else if (attr->name() == nameAttr) {
388 const AtomicString& newName = attr->value();
389 if (inDocument() && document()->isHTMLDocument()) {
390 HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
391 document->removeNamedItem(m_name);
392 document->addNamedItem(newName);
393 }
394 m_name = newName;
395 } else
396 HTMLElement::parseMappedAttribute(attr);
397 }
398
removeFromVector(Vector<T *,n> & vec,T * item)399 template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
400 {
401 size_t size = vec.size();
402 for (size_t i = 0; i != size; ++i)
403 if (vec[i] == item) {
404 vec.remove(i);
405 break;
406 }
407 }
408
formElementIndexWithFormAttribute(Element * element)409 unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element)
410 {
411 // Compares the position of the form element and the inserted element.
412 // Updates the indeces in order to the relation of the position:
413 unsigned short position = compareDocumentPosition(element);
414 if (position & (DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_CONTAINED_BY))
415 ++m_associatedElementsAfterIndex;
416 else if (position & DOCUMENT_POSITION_PRECEDING) {
417 ++m_associatedElementsBeforeIndex;
418 ++m_associatedElementsAfterIndex;
419 }
420
421 if (m_associatedElements.isEmpty())
422 return 0;
423
424 // Does binary search on m_associatedElements in order to find the index
425 // to be inserted.
426 unsigned left = 0, right = m_associatedElements.size() - 1;
427 while (left != right) {
428 unsigned middle = left + ((right - left) / 2);
429 position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
430 if (position & DOCUMENT_POSITION_FOLLOWING)
431 right = middle;
432 else
433 left = middle + 1;
434 }
435
436 position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
437 if (position & DOCUMENT_POSITION_FOLLOWING)
438 return left;
439 return left + 1;
440 }
441
formElementIndex(FormAssociatedElement * associatedElement)442 unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
443 {
444 HTMLElement* element = toHTMLElement(associatedElement);
445 // Treats separately the case where this element has the form attribute
446 // for performance consideration.
447 if (element->fastHasAttribute(formAttr))
448 return formElementIndexWithFormAttribute(element);
449
450 // Check for the special case where this element is the very last thing in
451 // the form's tree of children; we don't want to walk the entire tree in that
452 // common case that occurs during parsing; instead we'll just return a value
453 // that says "add this form element to the end of the array".
454 if (element->traverseNextNode(this)) {
455 unsigned i = m_associatedElementsBeforeIndex;
456 for (Node* node = this; node; node = node->traverseNextNode(this)) {
457 if (node == element) {
458 ++m_associatedElementsAfterIndex;
459 return i;
460 }
461 if (node->isHTMLElement()
462 && (static_cast<Element*>(node)->isFormControlElement()
463 || node->hasTagName(objectTag))
464 && toHTMLElement(node)->form() == this)
465 ++i;
466 }
467 }
468 return m_associatedElementsAfterIndex++;
469 }
470
registerFormElement(FormAssociatedElement * e)471 void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
472 {
473 if (e->isFormControlElement()) {
474 HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(e);
475 document()->checkedRadioButtons().removeButton(element);
476 m_checkedRadioButtons.addButton(element);
477 }
478 m_associatedElements.insert(formElementIndex(e), e);
479 }
480
removeFormElement(FormAssociatedElement * e)481 void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
482 {
483 if (e->isFormControlElement())
484 m_checkedRadioButtons.removeButton(static_cast<HTMLFormControlElement*>(e));
485 unsigned index;
486 for (index = 0; index < m_associatedElements.size(); ++index) {
487 if (m_associatedElements[index] == e)
488 break;
489 }
490 ASSERT(index < m_associatedElements.size());
491 if (index < m_associatedElementsBeforeIndex)
492 --m_associatedElementsBeforeIndex;
493 if (index < m_associatedElementsAfterIndex)
494 --m_associatedElementsAfterIndex;
495 removeFromVector(m_associatedElements, e);
496 }
497
isURLAttribute(Attribute * attr) const498 bool HTMLFormElement::isURLAttribute(Attribute* attr) const
499 {
500 return attr->name() == actionAttr;
501 }
502
registerImgElement(HTMLImageElement * e)503 void HTMLFormElement::registerImgElement(HTMLImageElement* e)
504 {
505 ASSERT(m_imageElements.find(e) == notFound);
506 m_imageElements.append(e);
507 }
508
removeImgElement(HTMLImageElement * e)509 void HTMLFormElement::removeImgElement(HTMLImageElement* e)
510 {
511 ASSERT(m_imageElements.find(e) != notFound);
512 removeFromVector(m_imageElements, e);
513 }
514
elements()515 PassRefPtr<HTMLCollection> HTMLFormElement::elements()
516 {
517 return HTMLFormCollection::create(this);
518 }
519
name() const520 String HTMLFormElement::name() const
521 {
522 return getAttribute(nameAttr);
523 }
524
noValidate() const525 bool HTMLFormElement::noValidate() const
526 {
527 return fastHasAttribute(novalidateAttr);
528 }
529
530 // FIXME: This function should be removed because it does not do the same thing as the
531 // JavaScript binding for action, which treats action as a URL attribute. Last time I
532 // (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
action() const533 String HTMLFormElement::action() const
534 {
535 return getAttribute(actionAttr);
536 }
537
setAction(const String & value)538 void HTMLFormElement::setAction(const String &value)
539 {
540 setAttribute(actionAttr, value);
541 }
542
setEnctype(const String & value)543 void HTMLFormElement::setEnctype(const String &value)
544 {
545 setAttribute(enctypeAttr, value);
546 }
547
method() const548 String HTMLFormElement::method() const
549 {
550 return getAttribute(methodAttr);
551 }
552
setMethod(const String & value)553 void HTMLFormElement::setMethod(const String &value)
554 {
555 setAttribute(methodAttr, value);
556 }
557
target() const558 String HTMLFormElement::target() const
559 {
560 return getAttribute(targetAttr);
561 }
562
wasUserSubmitted() const563 bool HTMLFormElement::wasUserSubmitted() const
564 {
565 return m_wasUserSubmitted;
566 }
567
defaultButton() const568 HTMLFormControlElement* HTMLFormElement::defaultButton() const
569 {
570 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
571 if (!m_associatedElements[i]->isFormControlElement())
572 continue;
573 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(m_associatedElements[i]);
574 if (control->isSuccessfulSubmitButton())
575 return control;
576 }
577
578 return 0;
579 }
580
checkValidity()581 bool HTMLFormElement::checkValidity()
582 {
583 Vector<RefPtr<FormAssociatedElement> > controls;
584 return !checkInvalidControlsAndCollectUnhandled(controls);
585 }
586
checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement>> & unhandledInvalidControls)587 bool HTMLFormElement::checkInvalidControlsAndCollectUnhandled(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
588 {
589 RefPtr<HTMLFormElement> protector(this);
590 // Copy m_associatedElements because event handlers called from
591 // HTMLFormControlElement::checkValidity() might change m_associatedElements.
592 Vector<RefPtr<FormAssociatedElement> > elements;
593 elements.reserveCapacity(m_associatedElements.size());
594 for (unsigned i = 0; i < m_associatedElements.size(); ++i)
595 elements.append(m_associatedElements[i]);
596 bool hasInvalidControls = false;
597 for (unsigned i = 0; i < elements.size(); ++i) {
598 if (elements[i]->form() == this && elements[i]->isFormControlElement()) {
599 HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(elements[i].get());
600 if (!control->checkValidity(&unhandledInvalidControls) && control->form() == this)
601 hasInvalidControls = true;
602 }
603 }
604 return hasInvalidControls;
605 }
606
elementForAlias(const AtomicString & alias)607 HTMLFormControlElement* HTMLFormElement::elementForAlias(const AtomicString& alias)
608 {
609 if (alias.isEmpty() || !m_elementAliases)
610 return 0;
611 return m_elementAliases->get(alias.impl()).get();
612 }
613
addElementAlias(HTMLFormControlElement * element,const AtomicString & alias)614 void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
615 {
616 if (alias.isEmpty())
617 return;
618 if (!m_elementAliases)
619 m_elementAliases = adoptPtr(new AliasMap);
620 m_elementAliases->set(alias.impl(), element);
621 }
622
getNamedElements(const AtomicString & name,Vector<RefPtr<Node>> & namedItems)623 void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
624 {
625 elements()->namedItems(name, namedItems);
626
627 HTMLFormControlElement* aliasElement = elementForAlias(name);
628 if (aliasElement) {
629 if (namedItems.find(aliasElement) == notFound) {
630 // We have seen it before but it is gone now. Still, we need to return it.
631 // FIXME: The above comment is not clear enough; it does not say why we need to do this.
632 namedItems.append(aliasElement);
633 }
634 }
635 if (namedItems.size() && namedItems.first() != aliasElement)
636 addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
637 }
638
documentDidBecomeActive()639 void HTMLFormElement::documentDidBecomeActive()
640 {
641 ASSERT(!autoComplete());
642
643 for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
644 if (m_associatedElements[i]->isFormControlElement())
645 static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
646 }
647 }
648
willMoveToNewOwnerDocument()649 void HTMLFormElement::willMoveToNewOwnerDocument()
650 {
651 if (!autoComplete())
652 document()->unregisterForDocumentActivationCallbacks(this);
653 HTMLElement::willMoveToNewOwnerDocument();
654 }
655
didMoveToNewOwnerDocument()656 void HTMLFormElement::didMoveToNewOwnerDocument()
657 {
658 if (!autoComplete())
659 document()->registerForDocumentActivationCallbacks(this);
660 HTMLElement::didMoveToNewOwnerDocument();
661 }
662
autoComplete() const663 bool HTMLFormElement::autoComplete() const
664 {
665 return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
666 }
667
668 } // namespace
669