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