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 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 "HTMLFormControlElement.h" 27 28 #include "Attribute.h" 29 #include "Chrome.h" 30 #include "ChromeClient.h" 31 #include "Document.h" 32 #include "DocumentParser.h" 33 #include "ElementRareData.h" 34 #include "Event.h" 35 #include "EventHandler.h" 36 #include "EventNames.h" 37 #include "Frame.h" 38 #include "HTMLFormElement.h" 39 #include "HTMLInputElement.h" 40 #include "HTMLNames.h" 41 #include "LabelsNodeList.h" 42 #include "Page.h" 43 #include "RenderBox.h" 44 #include "RenderTextControl.h" 45 #include "RenderTheme.h" 46 #include "ScriptEventListener.h" 47 #include "ValidationMessage.h" 48 #include "ValidityState.h" 49 #include <limits> 50 #include <wtf/Vector.h> 51 #include <wtf/unicode/CharacterNames.h> 52 53 namespace WebCore { 54 55 using namespace HTMLNames; 56 using namespace std; 57 58 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) 59 : HTMLElement(tagName, document) 60 , FormAssociatedElement(form) 61 , m_disabled(false) 62 , m_readOnly(false) 63 , m_required(false) 64 , m_valueMatchesRenderer(false) 65 , m_willValidateInitialized(false) 66 , m_willValidate(true) 67 , m_isValid(true) 68 , m_wasChangedSinceLastFormControlChangeEvent(false) 69 { 70 if (!this->form()) 71 setForm(findFormAncestor()); 72 if (this->form()) 73 this->form()->registerFormElement(this); 74 } 75 76 HTMLFormControlElement::~HTMLFormControlElement() 77 { 78 if (form()) 79 form()->removeFormElement(this); 80 } 81 82 void HTMLFormControlElement::detach() 83 { 84 m_validationMessage = 0; 85 HTMLElement::detach(); 86 } 87 88 bool HTMLFormControlElement::formNoValidate() const 89 { 90 return fastHasAttribute(formnovalidateAttr); 91 } 92 93 void HTMLFormControlElement::parseMappedAttribute(Attribute* attr) 94 { 95 if (attr->name() == disabledAttr) { 96 bool oldDisabled = m_disabled; 97 m_disabled = !attr->isNull(); 98 if (oldDisabled != m_disabled) { 99 setNeedsStyleRecalc(); 100 if (renderer() && renderer()->style()->hasAppearance()) 101 renderer()->theme()->stateChanged(renderer(), EnabledState); 102 } 103 } else if (attr->name() == readonlyAttr) { 104 bool oldReadOnly = m_readOnly; 105 m_readOnly = !attr->isNull(); 106 if (oldReadOnly != m_readOnly) { 107 setNeedsStyleRecalc(); 108 if (renderer() && renderer()->style()->hasAppearance()) 109 renderer()->theme()->stateChanged(renderer(), ReadOnlyState); 110 } 111 } else if (attr->name() == requiredAttr) { 112 bool oldRequired = m_required; 113 m_required = !attr->isNull(); 114 if (oldRequired != m_required) { 115 setNeedsValidityCheck(); 116 setNeedsStyleRecalc(); // Updates for :required :optional classes. 117 } 118 } else 119 HTMLElement::parseMappedAttribute(attr); 120 setNeedsWillValidateCheck(); 121 } 122 123 static bool shouldAutofocus(HTMLFormControlElement* element) 124 { 125 if (!element->autofocus()) 126 return false; 127 if (!element->renderer()) 128 return false; 129 if (element->document()->ignoreAutofocus()) 130 return false; 131 if (element->isReadOnlyFormControl()) 132 return false; 133 134 // FIXME: Should this set of hasTagName checks be replaced by a 135 // virtual member function? 136 if (element->hasTagName(inputTag)) 137 return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden(); 138 if (element->hasTagName(selectTag)) 139 return true; 140 if (element->hasTagName(keygenTag)) 141 return true; 142 if (element->hasTagName(buttonTag)) 143 return true; 144 if (element->hasTagName(textareaTag)) 145 return true; 146 147 return false; 148 } 149 150 static void focusPostAttach(Node* element) 151 { 152 static_cast<Element*>(element)->focus(); 153 element->deref(); 154 } 155 156 void HTMLFormControlElement::attach() 157 { 158 ASSERT(!attached()); 159 160 suspendPostAttachCallbacks(); 161 162 HTMLElement::attach(); 163 164 // The call to updateFromElement() needs to go after the call through 165 // to the base class's attach() because that can sometimes do a close 166 // on the renderer. 167 if (renderer()) 168 renderer()->updateFromElement(); 169 170 if (shouldAutofocus(this)) { 171 ref(); 172 queuePostAttachCallback(focusPostAttach, this); 173 } 174 175 resumePostAttachCallbacks(); 176 } 177 178 void HTMLFormControlElement::willMoveToNewOwnerDocument() 179 { 180 FormAssociatedElement::willMoveToNewOwnerDocument(); 181 HTMLElement::willMoveToNewOwnerDocument(); 182 } 183 184 void HTMLFormControlElement::insertedIntoTree(bool deep) 185 { 186 FormAssociatedElement::insertedIntoTree(); 187 if (!form()) 188 document()->checkedRadioButtons().addButton(this); 189 190 HTMLElement::insertedIntoTree(deep); 191 } 192 193 void HTMLFormControlElement::removedFromTree(bool deep) 194 { 195 FormAssociatedElement::removedFromTree(); 196 HTMLElement::removedFromTree(deep); 197 } 198 199 void HTMLFormControlElement::insertedIntoDocument() 200 { 201 HTMLElement::insertedIntoDocument(); 202 FormAssociatedElement::insertedIntoDocument(); 203 } 204 205 void HTMLFormControlElement::removedFromDocument() 206 { 207 HTMLElement::removedFromDocument(); 208 FormAssociatedElement::removedFromDocument(); 209 } 210 211 const AtomicString& HTMLFormControlElement::formControlName() const 212 { 213 const AtomicString& name = fastGetAttribute(nameAttr); 214 return name.isNull() ? emptyAtom : name; 215 } 216 217 void HTMLFormControlElement::setName(const AtomicString& value) 218 { 219 setAttribute(nameAttr, value); 220 } 221 222 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const 223 { 224 return m_wasChangedSinceLastFormControlChangeEvent; 225 } 226 227 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed) 228 { 229 m_wasChangedSinceLastFormControlChangeEvent = changed; 230 } 231 232 void HTMLFormControlElement::dispatchFormControlChangeEvent() 233 { 234 HTMLElement::dispatchChangeEvent(); 235 setChangedSinceLastFormControlChangeEvent(false); 236 } 237 238 void HTMLFormControlElement::dispatchFormControlInputEvent() 239 { 240 setChangedSinceLastFormControlChangeEvent(true); 241 HTMLElement::dispatchInputEvent(); 242 } 243 244 void HTMLFormControlElement::setDisabled(bool b) 245 { 246 setAttribute(disabledAttr, b ? "" : 0); 247 } 248 249 bool HTMLFormControlElement::autofocus() const 250 { 251 return hasAttribute(autofocusAttr); 252 } 253 254 bool HTMLFormControlElement::required() const 255 { 256 return m_required; 257 } 258 259 static void updateFromElementCallback(Node* node) 260 { 261 ASSERT_ARG(node, node->isElementNode()); 262 ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement()); 263 ASSERT(node->renderer()); 264 if (RenderObject* renderer = node->renderer()) 265 renderer->updateFromElement(); 266 } 267 268 void HTMLFormControlElement::recalcStyle(StyleChange change) 269 { 270 HTMLElement::recalcStyle(change); 271 272 // updateFromElement() can cause the selection to change, and in turn 273 // trigger synchronous layout, so it must not be called during style recalc. 274 if (renderer()) 275 queuePostAttachCallback(updateFromElementCallback, this); 276 } 277 278 bool HTMLFormControlElement::supportsFocus() const 279 { 280 return !m_disabled; 281 } 282 283 bool HTMLFormControlElement::isFocusable() const 284 { 285 if (!renderer() || 286 !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty()) 287 return false; 288 // HTMLElement::isFocusable handles visibility and calls suportsFocus which 289 // will cover the disabled case. 290 return HTMLElement::isFocusable(); 291 } 292 293 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const 294 { 295 if (isFocusable()) 296 if (document()->frame()) 297 return document()->frame()->eventHandler()->tabsToAllFormControls(event); 298 return false; 299 } 300 301 bool HTMLFormControlElement::isMouseFocusable() const 302 { 303 #if PLATFORM(GTK) || PLATFORM(QT) 304 return HTMLElement::isMouseFocusable(); 305 #else 306 return false; 307 #endif 308 } 309 310 short HTMLFormControlElement::tabIndex() const 311 { 312 // Skip the supportsFocus check in HTMLElement. 313 return Element::tabIndex(); 314 } 315 316 bool HTMLFormControlElement::recalcWillValidate() const 317 { 318 // FIXME: Should return false if this element has a datalist element as an 319 // ancestor. See HTML5 4.10.10 'The datalist element.' 320 return !m_disabled && !m_readOnly; 321 } 322 323 bool HTMLFormControlElement::willValidate() const 324 { 325 if (!m_willValidateInitialized) { 326 m_willValidateInitialized = true; 327 m_willValidate = recalcWillValidate(); 328 } else { 329 // If the following assertion fails, setNeedsWillValidateCheck() is not 330 // called correctly when something which changes recalcWillValidate() result 331 // is updated. 332 ASSERT(m_willValidate == recalcWillValidate()); 333 } 334 return m_willValidate; 335 } 336 337 void HTMLFormControlElement::setNeedsWillValidateCheck() 338 { 339 // We need to recalculate willValidte immediately because willValidate 340 // change can causes style change. 341 bool newWillValidate = recalcWillValidate(); 342 if (m_willValidateInitialized && m_willValidate == newWillValidate) 343 return; 344 m_willValidateInitialized = true; 345 m_willValidate = newWillValidate; 346 setNeedsStyleRecalc(); 347 if (!m_willValidate) 348 hideVisibleValidationMessage(); 349 } 350 351 String HTMLFormControlElement::validationMessage() 352 { 353 return validity()->validationMessage(); 354 } 355 356 void HTMLFormControlElement::updateVisibleValidationMessage() 357 { 358 Page* page = document()->page(); 359 if (!page) 360 return; 361 String message; 362 if (renderer() && willValidate()) { 363 message = validationMessage().stripWhiteSpace(); 364 // HTML5 specification doesn't ask UA to show the title attribute value 365 // with the validationMessage. However, this behavior is same as Opera 366 // and the specification describes such behavior as an example. 367 const AtomicString& title = getAttribute(titleAttr); 368 if (!message.isEmpty() && !title.isEmpty()) { 369 message.append('\n'); 370 message.append(title); 371 } 372 } 373 if (message.isEmpty()) { 374 hideVisibleValidationMessage(); 375 return; 376 } 377 if (!m_validationMessage) { 378 m_validationMessage = ValidationMessage::create(this); 379 m_validationMessage->setMessage(message); 380 } else { 381 // Call setMessage() even if m_validationMesage->message() == message 382 // because the existing message might be to be hidden. 383 m_validationMessage->setMessage(message); 384 } 385 } 386 387 void HTMLFormControlElement::hideVisibleValidationMessage() 388 { 389 if (m_validationMessage) 390 m_validationMessage->requestToHideMessage(); 391 } 392 393 String HTMLFormControlElement::visibleValidationMessage() const 394 { 395 return m_validationMessage ? m_validationMessage->message() : String(); 396 } 397 398 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls) 399 { 400 if (!willValidate() || isValidFormControlElement()) 401 return true; 402 // An event handler can deref this object. 403 RefPtr<HTMLFormControlElement> protector(this); 404 RefPtr<Document> originalDocument(document()); 405 bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true)); 406 if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document()) 407 unhandledInvalidControls->append(this); 408 return false; 409 } 410 411 bool HTMLFormControlElement::isValidFormControlElement() 412 { 413 // If the following assertion fails, setNeedsValidityCheck() is not called 414 // correctly when something which changes validity is updated. 415 ASSERT(m_isValid == validity()->valid()); 416 return m_isValid; 417 } 418 419 void HTMLFormControlElement::setNeedsValidityCheck() 420 { 421 bool newIsValid = validity()->valid(); 422 if (willValidate() && newIsValid != m_isValid) { 423 // Update style for pseudo classes such as :valid :invalid. 424 setNeedsStyleRecalc(); 425 } 426 m_isValid = newIsValid; 427 428 // Updates only if this control already has a validtion message. 429 if (!visibleValidationMessage().isEmpty()) { 430 // Calls updateVisibleValidationMessage() even if m_isValid is not 431 // changed because a validation message can be chagned. 432 updateVisibleValidationMessage(); 433 } 434 } 435 436 void HTMLFormControlElement::setCustomValidity(const String& error) 437 { 438 validity()->setCustomErrorMessage(error); 439 } 440 441 void HTMLFormControlElement::dispatchFocusEvent() 442 { 443 if (document()->page()) 444 document()->page()->chrome()->client()->formDidFocus(this); 445 446 HTMLElement::dispatchFocusEvent(); 447 } 448 449 void HTMLFormControlElement::dispatchBlurEvent() 450 { 451 if (document()->page()) 452 document()->page()->chrome()->client()->formDidBlur(this); 453 454 HTMLElement::dispatchBlurEvent(); 455 hideVisibleValidationMessage(); 456 } 457 458 HTMLFormElement* HTMLFormControlElement::virtualForm() const 459 { 460 return FormAssociatedElement::form(); 461 } 462 463 bool HTMLFormControlElement::isDefaultButtonForForm() const 464 { 465 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this; 466 } 467 468 void HTMLFormControlElement::attributeChanged(Attribute* attr, bool preserveDecls) 469 { 470 if (attr->name() == formAttr) { 471 formAttributeChanged(); 472 if (!form()) 473 document()->checkedRadioButtons().addButton(this); 474 } else 475 HTMLElement::attributeChanged(attr, preserveDecls); 476 } 477 478 bool HTMLFormControlElement::isLabelable() const 479 { 480 // FIXME: Add meterTag and outputTag to the list once we support them. 481 return hasTagName(buttonTag) || hasTagName(inputTag) || hasTagName(keygenTag) 482 #if ENABLE(METER_TAG) 483 || hasTagName(meterTag) 484 #endif 485 #if ENABLE(PROGRESS_TAG) 486 || hasTagName(progressTag) 487 #endif 488 || hasTagName(selectTag) || hasTagName(textareaTag); 489 } 490 491 PassRefPtr<NodeList> HTMLFormControlElement::labels() 492 { 493 if (!isLabelable()) 494 return 0; 495 if (!document()) 496 return 0; 497 498 NodeRareData* data = Node::ensureRareData(); 499 if (!data->nodeLists()) { 500 data->setNodeLists(NodeListsNodeData::create()); 501 document()->addNodeListCache(); 502 } 503 504 return LabelsNodeList::create(this); 505 } 506 507 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) 508 : HTMLFormControlElement(tagName, doc, f) 509 { 510 document()->registerFormElementWithState(this); 511 } 512 513 HTMLFormControlElementWithState::~HTMLFormControlElementWithState() 514 { 515 document()->unregisterFormElementWithState(this); 516 } 517 518 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument() 519 { 520 document()->unregisterFormElementWithState(this); 521 HTMLFormControlElement::willMoveToNewOwnerDocument(); 522 } 523 524 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument() 525 { 526 document()->registerFormElementWithState(this); 527 HTMLFormControlElement::didMoveToNewOwnerDocument(); 528 } 529 530 bool HTMLFormControlElementWithState::autoComplete() const 531 { 532 if (!form()) 533 return true; 534 return form()->autoComplete(); 535 } 536 537 bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const 538 { 539 // We don't save/restore control state in a form with autocomplete=off. 540 return attached() && autoComplete(); 541 } 542 543 void HTMLFormControlElementWithState::finishParsingChildren() 544 { 545 HTMLFormControlElement::finishParsingChildren(); 546 547 // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false. 548 // But we need to skip restoring process too because a control in another 549 // form might have the same pair of name and type and saved its state. 550 if (!shouldSaveAndRestoreFormControlState()) 551 return; 552 553 Document* doc = document(); 554 if (doc->hasStateForNewFormElements()) { 555 String state; 556 if (doc->takeStateForFormElement(name().impl(), type().impl(), state)) 557 restoreFormControlState(state); 558 } 559 } 560 561 void HTMLFormControlElementWithState::defaultEventHandler(Event* event) 562 { 563 if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) { 564 toRenderTextControl(renderer())->subtreeHasChanged(); 565 return; 566 } 567 568 HTMLFormControlElement::defaultEventHandler(event); 569 } 570 571 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form) 572 : HTMLFormControlElementWithState(tagName, doc, form) 573 { 574 } 575 576 HTMLTextFormControlElement::~HTMLTextFormControlElement() 577 { 578 } 579 580 void HTMLTextFormControlElement::insertedIntoDocument() 581 { 582 HTMLFormControlElement::insertedIntoDocument(); 583 setTextAsOfLastFormControlChangeEvent(value()); 584 } 585 586 void HTMLTextFormControlElement::dispatchFocusEvent() 587 { 588 if (supportsPlaceholder()) 589 updatePlaceholderVisibility(false); 590 handleFocusEvent(); 591 HTMLFormControlElementWithState::dispatchFocusEvent(); 592 } 593 594 void HTMLTextFormControlElement::dispatchBlurEvent() 595 { 596 if (supportsPlaceholder()) 597 updatePlaceholderVisibility(false); 598 handleBlurEvent(); 599 HTMLFormControlElementWithState::dispatchBlurEvent(); 600 } 601 602 String HTMLTextFormControlElement::strippedPlaceholder() const 603 { 604 // According to the HTML5 specification, we need to remove CR and LF from 605 // the attribute value. 606 const AtomicString& attributeValue = getAttribute(placeholderAttr); 607 if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn)) 608 return attributeValue; 609 610 Vector<UChar> stripped; 611 unsigned length = attributeValue.length(); 612 stripped.reserveCapacity(length); 613 for (unsigned i = 0; i < length; ++i) { 614 UChar character = attributeValue[i]; 615 if (character == newlineCharacter || character == carriageReturn) 616 continue; 617 stripped.append(character); 618 } 619 return String::adopt(stripped); 620 } 621 622 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; } 623 624 bool HTMLTextFormControlElement::isPlaceholderEmpty() const 625 { 626 const AtomicString& attributeValue = getAttribute(placeholderAttr); 627 return attributeValue.string().find(isNotLineBreak) == notFound; 628 } 629 630 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const 631 { 632 return supportsPlaceholder() 633 && isEmptyValue() 634 && isEmptySuggestedValue() 635 && !isPlaceholderEmpty() 636 && (document()->focusedNode() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused())); 637 } 638 639 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged) 640 { 641 if (supportsPlaceholder() && renderer()) 642 toRenderTextControl(renderer())->updatePlaceholderVisibility(placeholderShouldBeVisible(), placeholderValueChanged); 643 } 644 645 RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout() 646 { 647 if (!isTextFormControl()) 648 return 0; 649 document()->updateLayoutIgnorePendingStylesheets(); 650 return toRenderTextControl(renderer()); 651 } 652 653 void HTMLTextFormControlElement::setSelectionStart(int start) 654 { 655 setSelectionRange(start, max(start, selectionEnd())); 656 } 657 658 void HTMLTextFormControlElement::setSelectionEnd(int end) 659 { 660 setSelectionRange(min(end, selectionStart()), end); 661 } 662 663 void HTMLTextFormControlElement::select() 664 { 665 setSelectionRange(0, numeric_limits<int>::max()); 666 } 667 668 void HTMLTextFormControlElement::dispatchFormControlChangeEvent() 669 { 670 if (m_textAsOfLastFormControlChangeEvent != value()) { 671 HTMLElement::dispatchChangeEvent(); 672 setTextAsOfLastFormControlChangeEvent(value()); 673 } 674 setChangedSinceLastFormControlChangeEvent(false); 675 } 676 677 void HTMLTextFormControlElement::setSelectionRange(int start, int end) 678 { 679 WebCore::setSelectionRange(this, start, end); 680 } 681 682 int HTMLTextFormControlElement::selectionStart() const 683 { 684 if (!isTextFormControl()) 685 return 0; 686 if (document()->focusedNode() != this && cachedSelectionStart() >= 0) 687 return cachedSelectionStart(); 688 if (!renderer()) 689 return 0; 690 return toRenderTextControl(renderer())->selectionStart(); 691 } 692 693 int HTMLTextFormControlElement::selectionEnd() const 694 { 695 if (!isTextFormControl()) 696 return 0; 697 if (document()->focusedNode() != this && cachedSelectionEnd() >= 0) 698 return cachedSelectionEnd(); 699 if (!renderer()) 700 return 0; 701 return toRenderTextControl(renderer())->selectionEnd(); 702 } 703 704 PassRefPtr<Range> HTMLTextFormControlElement::selection() const 705 { 706 if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0) 707 return 0; 708 return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd()); 709 } 710 711 void HTMLTextFormControlElement::parseMappedAttribute(Attribute* attr) 712 { 713 if (attr->name() == placeholderAttr) 714 updatePlaceholderVisibility(true); 715 else if (attr->name() == onselectAttr) 716 setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr)); 717 else if (attr->name() == onchangeAttr) 718 setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr)); 719 else 720 HTMLFormControlElementWithState::parseMappedAttribute(attr); 721 } 722 723 } // namespace Webcore 724