1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 * 23 */ 24 25 #include "config.h" 26 #include "HTMLFormElement.h" 27 28 #include "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 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 80 PassRefPtr<HTMLFormElement> HTMLFormElement::create(Document* document) 81 { 82 return adoptRef(new HTMLFormElement(formTag, document)); 83 } 84 85 PassRefPtr<HTMLFormElement> HTMLFormElement::create(const QualifiedName& tagName, Document* document) 86 { 87 return adoptRef(new HTMLFormElement(tagName, document)); 88 } 89 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 101 bool HTMLFormElement::formWouldHaveSecureSubmission(const String& url) 102 { 103 return document()->completeURL(url).protocolIs("https"); 104 } 105 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 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 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 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 163 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 172 Node* HTMLFormElement::item(unsigned index) 173 { 174 return elements()->item(index); 175 } 176 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 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 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 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 289 void HTMLFormElement::submit() 290 { 291 submit(0, false, true, NotSubmittedByJavaScript); 292 } 293 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 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 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 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 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 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 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 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 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 498 bool HTMLFormElement::isURLAttribute(Attribute* attr) const 499 { 500 return attr->name() == actionAttr; 501 } 502 503 void HTMLFormElement::registerImgElement(HTMLImageElement* e) 504 { 505 ASSERT(m_imageElements.find(e) == notFound); 506 m_imageElements.append(e); 507 } 508 509 void HTMLFormElement::removeImgElement(HTMLImageElement* e) 510 { 511 ASSERT(m_imageElements.find(e) != notFound); 512 removeFromVector(m_imageElements, e); 513 } 514 515 PassRefPtr<HTMLCollection> HTMLFormElement::elements() 516 { 517 return HTMLFormCollection::create(this); 518 } 519 520 String HTMLFormElement::name() const 521 { 522 return getAttribute(nameAttr); 523 } 524 525 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. 533 String HTMLFormElement::action() const 534 { 535 return getAttribute(actionAttr); 536 } 537 538 void HTMLFormElement::setAction(const String &value) 539 { 540 setAttribute(actionAttr, value); 541 } 542 543 void HTMLFormElement::setEnctype(const String &value) 544 { 545 setAttribute(enctypeAttr, value); 546 } 547 548 String HTMLFormElement::method() const 549 { 550 return getAttribute(methodAttr); 551 } 552 553 void HTMLFormElement::setMethod(const String &value) 554 { 555 setAttribute(methodAttr, value); 556 } 557 558 String HTMLFormElement::target() const 559 { 560 return getAttribute(targetAttr); 561 } 562 563 bool HTMLFormElement::wasUserSubmitted() const 564 { 565 return m_wasUserSubmitted; 566 } 567 568 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 581 bool HTMLFormElement::checkValidity() 582 { 583 Vector<RefPtr<FormAssociatedElement> > controls; 584 return !checkInvalidControlsAndCollectUnhandled(controls); 585 } 586 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 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 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 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 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 649 void HTMLFormElement::willMoveToNewOwnerDocument() 650 { 651 if (!autoComplete()) 652 document()->unregisterForDocumentActivationCallbacks(this); 653 HTMLElement::willMoveToNewOwnerDocument(); 654 } 655 656 void HTMLFormElement::didMoveToNewOwnerDocument() 657 { 658 if (!autoComplete()) 659 document()->registerForDocumentActivationCallbacks(this); 660 HTMLElement::didMoveToNewOwnerDocument(); 661 } 662 663 bool HTMLFormElement::autoComplete() const 664 { 665 return !equalIgnoringCase(fastGetAttribute(autocompleteAttr), "off"); 666 } 667 668 } // namespace 669