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
60using namespace std;
61
62namespace WebCore {
63
64using namespace HTMLNames;
65
66HTMLFormElement::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
80PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document)
81{
82    return adoptRef(new HTMLFormElement(formTag, document));
83}
84
85PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document)
86{
87    return adoptRef(new HTMLFormElement(tagName, document));
88}
89
90HTMLFormElement::~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
101bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url)
102{
103    return document()->completeURL(url).protocolIs("https");
104}
105
106bool 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
131void 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
142void 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
153void 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
163unsigned 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
172Node* HTMLFormElement::item(unsigned index)
173{
174    return elements()->item(index);
175}
176
177void 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
197static 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
208bool 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
261bool 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
289void HTMLFormElement::submit()
290{
291    submit(0, false, true, NotSubmittedByJavaScript);
292}
293
294void HTMLFormElement::submitFromJavaScript()
295{
296    Frame* frame = document()->frame();
297    if (!frame)
298        return;
299    submit(0, false, frame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
300}
301
302void 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
345void 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
366void 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
399template<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
409unsigned 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
442unsigned 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
471void 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
481void 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
498bool HTMLFormElement::isURLAttribute(Attribute* attr) const
499{
500    return attr->name() == actionAttr;
501}
502
503void HTMLFormElement::registerImgElement(HTMLImageElement* e)
504{
505    ASSERT(m_imageElements.find(e) == notFound);
506    m_imageElements.append(e);
507}
508
509void HTMLFormElement::removeImgElement(HTMLImageElement* e)
510{
511    ASSERT(m_imageElements.find(e) != notFound);
512    removeFromVector(m_imageElements, e);
513}
514
515PassRefPtr<HTMLCollection> HTMLFormElement::elements()
516{
517    return HTMLFormCollection::create(this);
518}
519
520String HTMLFormElement::name() const
521{
522    return getAttribute(nameAttr);
523}
524
525bool 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.
533String HTMLFormElement::action() const
534{
535    return getAttribute(actionAttr);
536}
537
538void HTMLFormElement::setAction(const String &value)
539{
540    setAttribute(actionAttr, value);
541}
542
543void HTMLFormElement::setEnctype(const String &value)
544{
545    setAttribute(enctypeAttr, value);
546}
547
548String HTMLFormElement::method() const
549{
550    return getAttribute(methodAttr);
551}
552
553void HTMLFormElement::setMethod(const String &value)
554{
555    setAttribute(methodAttr, value);
556}
557
558String HTMLFormElement::target() const
559{
560    return getAttribute(targetAttr);
561}
562
563bool HTMLFormElement::wasUserSubmitted() const
564{
565    return m_wasUserSubmitted;
566}
567
568HTMLFormControlElement* 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
581bool HTMLFormElement::checkValidity()
582{
583    Vector<RefPtr<FormAssociatedElement> > controls;
584    return !checkInvalidControlsAndCollectUnhandled(controls);
585}
586
587bool 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
607HTMLFormControlElement* 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
614void 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
623void 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
639void 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
649void HTMLFormElement::willMoveToNewOwnerDocument()
650{
651    if (!autoComplete())
652        document()->unregisterForDocumentActivationCallbacks(this);
653    HTMLElement::willMoveToNewOwnerDocument();
654}
655
656void HTMLFormElement::didMoveToNewOwnerDocument()
657{
658    if (!autoComplete())
659        document()->registerForDocumentActivationCallbacks(this);
660    HTMLElement::didMoveToNewOwnerDocument();
661}
662
663bool HTMLFormElement::autoComplete() const
664{
665    return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
666}
667
668} // namespace
669