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