HTMLFormElement.cpp revision cad810f21b803229eb11403f9209855525a25d57
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    collectUnhandledInvalidControls(unhandledInvalidControls);
225    if (unhandledInvalidControls.isEmpty())
226        return true;
227    // If the form has invalid controls, abort submission.
228
229    RefPtr<HTMLFormElement> protector(this);
230    // Focus on the first focusable control and show a validation message.
231    for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
232        FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
233        HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
234        if (unhandled->isFocusable() && unhandled->inDocument()) {
235            RefPtr<Document> originalDocument(unhandled->document());
236            unhandled->scrollIntoViewIfNeeded(false);
237            // scrollIntoViewIfNeeded() dispatches events, so the state
238            // of 'unhandled' might be changed so it's no longer focusable or
239            // moved to another document.
240            if (unhandled->isFocusable() && unhandled->inDocument() && originalDocument == unhandled->document()) {
241                unhandled->focus();
242                if (unhandled->isFormControlElement())
243                    static_cast<HTMLFormControlElement*>(unhandled)->updateVisibleValidationMessage();
244                break;
245            }
246        }
247    }
248    // Warn about all of unfocusable controls.
249    if (Frame* frame = document()->frame()) {
250        for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
251            FormAssociatedElement* unhandledAssociatedElement = unhandledInvalidControls[i].get();
252            HTMLElement* unhandled = toHTMLElement(unhandledAssociatedElement);
253            if (unhandled->isFocusable() && unhandled->inDocument())
254                continue;
255            String message("An invalid form control with name='%name' is not focusable.");
256            message.replace("%name", unhandledAssociatedElement->name());
257            frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string());
258        }
259    }
260    return false;
261}
262
263bool HTMLFormElement::prepareForSubmission(Event* event)
264{
265    Frame* frame = document()->frame();
266    if (m_isSubmittingOrPreparingForSubmission || !frame)
267        return m_isSubmittingOrPreparingForSubmission;
268
269    m_isSubmittingOrPreparingForSubmission = true;
270    m_shouldSubmit = false;
271
272    // Interactive validation must be done before dispatching the submit event.
273    if (!validateInteractively(event)) {
274        m_isSubmittingOrPreparingForSubmission = false;
275        return false;
276    }
277
278    frame->loader()->client()->dispatchWillSendSubmitEvent(this);
279
280    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)))
281        m_shouldSubmit = true;
282
283    m_isSubmittingOrPreparingForSubmission = false;
284
285    if (m_shouldSubmit)
286        submit(event, true, true, NotSubmittedByJavaScript);
287
288    return m_shouldSubmit;
289}
290
291void HTMLFormElement::submit()
292{
293    submit(0, false, true, NotSubmittedByJavaScript);
294}
295
296void HTMLFormElement::submitFromJavaScript()
297{
298    Frame* frame = document()->frame();
299    if (!frame)
300        return;
301    submit(0, false, frame->script()->anyPageIsProcessingUserGesture(), SubmittedByJavaScript);
302}
303
304void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool processingUserGesture, FormSubmissionTrigger formSubmissionTrigger)
305{
306    FrameView* view = document()->view();
307    Frame* frame = document()->frame();
308    if (!view || !frame)
309        return;
310
311    if (m_isSubmittingOrPreparingForSubmission) {
312        m_shouldSubmit = true;
313        return;
314    }
315
316    m_isSubmittingOrPreparingForSubmission = true;
317    m_wasUserSubmitted = processingUserGesture;
318
319    HTMLFormControlElement* firstSuccessfulSubmitButton = 0;
320    bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
321
322    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
323        FormAssociatedElement* associatedElement = m_associatedElements[i];
324        if (!associatedElement->isFormControlElement())
325            continue;
326        if (needButtonActivation) {
327            HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(associatedElement);
328            if (control->isActivatedSubmit())
329                needButtonActivation = false;
330            else if (firstSuccessfulSubmitButton == 0 && control->isSuccessfulSubmitButton())
331                firstSuccessfulSubmitButton = control;
332        }
333    }
334
335    if (needButtonActivation && firstSuccessfulSubmitButton)
336        firstSuccessfulSubmitButton->setActivatedSubmit(true);
337
338    frame->loader()->submitForm(FormSubmission::create(this, m_attributes, event, !processingUserGesture, formSubmissionTrigger));
339
340    if (needButtonActivation && firstSuccessfulSubmitButton)
341        firstSuccessfulSubmitButton->setActivatedSubmit(false);
342
343    m_shouldSubmit = false;
344    m_isSubmittingOrPreparingForSubmission = false;
345}
346
347void HTMLFormElement::reset()
348{
349    Frame* frame = document()->frame();
350    if (m_isInResetFunction || !frame)
351        return;
352
353    m_isInResetFunction = true;
354
355    if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
356        m_isInResetFunction = false;
357        return;
358    }
359
360    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
361        if (m_associatedElements[i]->isFormControlElement())
362            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
363    }
364
365    m_isInResetFunction = false;
366}
367
368void HTMLFormElement::parseMappedAttribute(Attribute* attr)
369{
370    if (attr->name() == actionAttr)
371        m_attributes.parseAction(attr->value());
372    else if (attr->name() == targetAttr)
373        m_attributes.setTarget(attr->value());
374    else if (attr->name() == methodAttr)
375        m_attributes.parseMethodType(attr->value());
376    else if (attr->name() == enctypeAttr)
377        m_attributes.parseEncodingType(attr->value());
378    else if (attr->name() == accept_charsetAttr)
379        m_attributes.setAcceptCharset(attr->value());
380    else if (attr->name() == autocompleteAttr) {
381        if (!autoComplete())
382            document()->registerForDocumentActivationCallbacks(this);
383        else
384            document()->unregisterForDocumentActivationCallbacks(this);
385    } else if (attr->name() == onsubmitAttr)
386        setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr));
387    else if (attr->name() == onresetAttr)
388        setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr));
389    else if (attr->name() == nameAttr) {
390        const AtomicString& newName = attr->value();
391        if (inDocument() && document()->isHTMLDocument()) {
392            HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
393            document->removeNamedItem(m_name);
394            document->addNamedItem(newName);
395        }
396        m_name = newName;
397    } else
398        HTMLElement::parseMappedAttribute(attr);
399}
400
401template<class T, size_t n> static void removeFromVector(Vector<T*, n> & vec, T* item)
402{
403    size_t size = vec.size();
404    for (size_t i = 0; i != size; ++i)
405        if (vec[i] == item) {
406            vec.remove(i);
407            break;
408        }
409}
410
411unsigned HTMLFormElement::formElementIndexWithFormAttribute(Element* element)
412{
413    // Compares the position of the form element and the inserted element.
414    // Updates the indeces in order to the relation of the position:
415    unsigned short position = compareDocumentPosition(element);
416    if (position & DOCUMENT_POSITION_CONTAINS)
417        ++m_associatedElementsAfterIndex;
418    else if (position & DOCUMENT_POSITION_PRECEDING) {
419        ++m_associatedElementsBeforeIndex;
420        ++m_associatedElementsAfterIndex;
421    }
422
423    if (m_associatedElements.isEmpty())
424        return 0;
425
426    // Does binary search on m_associatedElements in order to find the index
427    // to be inserted.
428    unsigned left = 0, right = m_associatedElements.size() - 1;
429    while (left != right) {
430        unsigned middle = left + ((right - left) / 2);
431        position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[middle]));
432        if (position & DOCUMENT_POSITION_FOLLOWING)
433            right = middle;
434        else
435            left = middle + 1;
436    }
437
438    position = element->compareDocumentPosition(toHTMLElement(m_associatedElements[left]));
439    if (position & DOCUMENT_POSITION_FOLLOWING)
440        return left;
441    return left + 1;
442}
443
444unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElement)
445{
446    HTMLElement* element = toHTMLElement(associatedElement);
447    // Treats separately the case where this element has the form attribute
448    // for performance consideration.
449    if (element->fastHasAttribute(formAttr))
450        return formElementIndexWithFormAttribute(element);
451
452    // Check for the special case where this element is the very last thing in
453    // the form's tree of children; we don't want to walk the entire tree in that
454    // common case that occurs during parsing; instead we'll just return a value
455    // that says "add this form element to the end of the array".
456    if (element->traverseNextNode(this)) {
457        unsigned i = m_associatedElementsBeforeIndex;
458        for (Node* node = this; node; node = node->traverseNextNode(this)) {
459            if (node == element) {
460                ++m_associatedElementsAfterIndex;
461                return i;
462            }
463            if (node->isHTMLElement()
464                    && (static_cast<Element*>(node)->isFormControlElement()
465                        || node->hasTagName(objectTag))
466                    && static_cast<HTMLElement*>(node)->form() == this)
467                ++i;
468        }
469    }
470    return m_associatedElementsAfterIndex++;
471}
472
473void HTMLFormElement::registerFormElement(FormAssociatedElement* e)
474{
475    if (e->isFormControlElement()) {
476        HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(e);
477        document()->checkedRadioButtons().removeButton(element);
478        m_checkedRadioButtons.addButton(element);
479    }
480    m_associatedElements.insert(formElementIndex(e), e);
481}
482
483void HTMLFormElement::removeFormElement(FormAssociatedElement* e)
484{
485    if (e->isFormControlElement())
486        m_checkedRadioButtons.removeButton(static_cast<HTMLFormControlElement*>(e));
487    HTMLElement* element = toHTMLElement(e);
488    if (element->fastHasAttribute(formAttr)) {
489        unsigned index;
490        for (index = 0; index < m_associatedElements.size(); ++index)
491            if (m_associatedElements[index] == e)
492                break;
493        ASSERT(index < m_associatedElements.size());
494        if (index < m_associatedElementsBeforeIndex)
495            --m_associatedElementsBeforeIndex;
496        if (index < m_associatedElementsAfterIndex)
497            --m_associatedElementsAfterIndex;
498    } else
499        --m_associatedElementsAfterIndex;
500    removeFromVector(m_associatedElements, e);
501}
502
503bool HTMLFormElement::isURLAttribute(Attribute* attr) const
504{
505    return attr->name() == actionAttr;
506}
507
508void HTMLFormElement::registerImgElement(HTMLImageElement* e)
509{
510    ASSERT(m_imageElements.find(e) == notFound);
511    m_imageElements.append(e);
512}
513
514void HTMLFormElement::removeImgElement(HTMLImageElement* e)
515{
516    ASSERT(m_imageElements.find(e) != notFound);
517    removeFromVector(m_imageElements, e);
518}
519
520PassRefPtr<HTMLCollection> HTMLFormElement::elements()
521{
522    return HTMLFormCollection::create(this);
523}
524
525String HTMLFormElement::name() const
526{
527    return getAttribute(nameAttr);
528}
529
530bool HTMLFormElement::noValidate() const
531{
532    return fastHasAttribute(novalidateAttr);
533}
534
535// FIXME: This function should be removed because it does not do the same thing as the
536// JavaScript binding for action, which treats action as a URL attribute. Last time I
537// (Darin Adler) removed this, someone added it back, so I am leaving it in for now.
538String HTMLFormElement::action() const
539{
540    return getAttribute(actionAttr);
541}
542
543void HTMLFormElement::setAction(const String &value)
544{
545    setAttribute(actionAttr, value);
546}
547
548void HTMLFormElement::setEnctype(const String &value)
549{
550    setAttribute(enctypeAttr, value);
551}
552
553String HTMLFormElement::method() const
554{
555    return getAttribute(methodAttr);
556}
557
558void HTMLFormElement::setMethod(const String &value)
559{
560    setAttribute(methodAttr, value);
561}
562
563String HTMLFormElement::target() const
564{
565    return getAttribute(targetAttr);
566}
567
568bool HTMLFormElement::wasUserSubmitted() const
569{
570    return m_wasUserSubmitted;
571}
572
573HTMLFormControlElement* HTMLFormElement::defaultButton() const
574{
575    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
576        if (!m_associatedElements[i]->isFormControlElement())
577            continue;
578        HTMLFormControlElement* control = static_cast<HTMLFormControlElement*>(m_associatedElements[i]);
579        if (control->isSuccessfulSubmitButton())
580            return control;
581    }
582
583    return 0;
584}
585
586bool HTMLFormElement::checkValidity()
587{
588    Vector<RefPtr<FormAssociatedElement> > controls;
589    collectUnhandledInvalidControls(controls);
590    return controls.isEmpty();
591}
592
593void HTMLFormElement::collectUnhandledInvalidControls(Vector<RefPtr<FormAssociatedElement> >& unhandledInvalidControls)
594{
595    RefPtr<HTMLFormElement> protector(this);
596    // Copy m_associatedElements because event handlers called from
597    // HTMLFormControlElement::checkValidity() might change m_associatedElements.
598    Vector<RefPtr<FormAssociatedElement> > elements;
599    elements.reserveCapacity(m_associatedElements.size());
600    for (unsigned i = 0; i < m_associatedElements.size(); ++i)
601        elements.append(m_associatedElements[i]);
602    for (unsigned i = 0; i < elements.size(); ++i) {
603        if (elements[i]->form() == this && elements[i]->isFormControlElement())
604            static_cast<HTMLFormControlElement*>(elements[i].get())->checkValidity(&unhandledInvalidControls);
605    }
606}
607
608HTMLFormControlElement* HTMLFormElement::elementForAlias(const AtomicString& alias)
609{
610    if (alias.isEmpty() || !m_elementAliases)
611        return 0;
612    return m_elementAliases->get(alias.impl()).get();
613}
614
615void HTMLFormElement::addElementAlias(HTMLFormControlElement* element, const AtomicString& alias)
616{
617    if (alias.isEmpty())
618        return;
619    if (!m_elementAliases)
620        m_elementAliases = adoptPtr(new AliasMap);
621    m_elementAliases->set(alias.impl(), element);
622}
623
624void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
625{
626    elements()->namedItems(name, namedItems);
627
628    HTMLFormControlElement* aliasElement = elementForAlias(name);
629    if (aliasElement) {
630        if (namedItems.find(aliasElement) == notFound) {
631            // We have seen it before but it is gone now. Still, we need to return it.
632            // FIXME: The above comment is not clear enough; it does not say why we need to do this.
633            namedItems.append(aliasElement);
634        }
635    }
636    if (namedItems.size() && namedItems.first() != aliasElement)
637        addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
638}
639
640void HTMLFormElement::documentDidBecomeActive()
641{
642    ASSERT(!autoComplete());
643
644    for (unsigned i = 0; i < m_associatedElements.size(); ++i) {
645        if (m_associatedElements[i]->isFormControlElement())
646            static_cast<HTMLFormControlElement*>(m_associatedElements[i])->reset();
647    }
648}
649
650void HTMLFormElement::willMoveToNewOwnerDocument()
651{
652    if (!autoComplete())
653        document()->unregisterForDocumentActivationCallbacks(this);
654    HTMLElement::willMoveToNewOwnerDocument();
655}
656
657void HTMLFormElement::didMoveToNewOwnerDocument()
658{
659    if (!autoComplete())
660        document()->registerForDocumentActivationCallbacks(this);
661    HTMLElement::didMoveToNewOwnerDocument();
662}
663
664bool HTMLFormElement::autoComplete() const
665{
666    return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off");
667}
668
669} // namespace
670