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 "core/html/HTMLFormControlElement.h" 27 28 #include "core/dom/ElementTraversal.h" 29 #include "core/events/Event.h" 30 #include "core/frame/UseCounter.h" 31 #include "core/html/HTMLDataListElement.h" 32 #include "core/html/HTMLFieldSetElement.h" 33 #include "core/html/HTMLFormElement.h" 34 #include "core/html/HTMLInputElement.h" 35 #include "core/html/HTMLLegendElement.h" 36 #include "core/html/ValidityState.h" 37 #include "core/inspector/ConsoleMessage.h" 38 #include "core/page/Page.h" 39 #include "core/page/ValidationMessageClient.h" 40 #include "core/rendering/RenderBox.h" 41 #include "core/rendering/RenderTheme.h" 42 #include "platform/text/BidiTextRun.h" 43 #include "wtf/Vector.h" 44 45 namespace blink { 46 47 using namespace HTMLNames; 48 49 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form) 50 : LabelableElement(tagName, document) 51 , m_disabled(false) 52 , m_isAutofilled(false) 53 , m_isReadOnly(false) 54 , m_isRequired(false) 55 , m_hasValidationMessage(false) 56 , m_ancestorDisabledState(AncestorDisabledStateUnknown) 57 , m_dataListAncestorState(Unknown) 58 , m_willValidateInitialized(false) 59 , m_willValidate(true) 60 , m_isValid(true) 61 , m_wasChangedSinceLastFormControlChangeEvent(false) 62 , m_wasFocusedByMouse(false) 63 { 64 setHasCustomStyleCallbacks(); 65 associateByParser(form); 66 } 67 68 HTMLFormControlElement::~HTMLFormControlElement() 69 { 70 #if !ENABLE(OILPAN) 71 setForm(0); 72 #endif 73 } 74 75 void HTMLFormControlElement::trace(Visitor* visitor) 76 { 77 FormAssociatedElement::trace(visitor); 78 LabelableElement::trace(visitor); 79 } 80 81 String HTMLFormControlElement::formEnctype() const 82 { 83 const AtomicString& formEnctypeAttr = fastGetAttribute(formenctypeAttr); 84 if (formEnctypeAttr.isNull()) 85 return emptyString(); 86 return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr); 87 } 88 89 void HTMLFormControlElement::setFormEnctype(const AtomicString& value) 90 { 91 setAttribute(formenctypeAttr, value); 92 } 93 94 String HTMLFormControlElement::formMethod() const 95 { 96 const AtomicString& formMethodAttr = fastGetAttribute(formmethodAttr); 97 if (formMethodAttr.isNull()) 98 return emptyString(); 99 return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr)); 100 } 101 102 void HTMLFormControlElement::setFormMethod(const AtomicString& value) 103 { 104 setAttribute(formmethodAttr, value); 105 } 106 107 bool HTMLFormControlElement::formNoValidate() const 108 { 109 return fastHasAttribute(formnovalidateAttr); 110 } 111 112 void HTMLFormControlElement::updateAncestorDisabledState() const 113 { 114 HTMLFieldSetElement* fieldSetAncestor = 0; 115 ContainerNode* legendAncestor = 0; 116 for (HTMLElement* ancestor = Traversal<HTMLElement>::firstAncestor(*this); ancestor; ancestor = Traversal<HTMLElement>::firstAncestor(*ancestor)) { 117 if (!legendAncestor && isHTMLLegendElement(*ancestor)) 118 legendAncestor = ancestor; 119 if (isHTMLFieldSetElement(*ancestor)) { 120 fieldSetAncestor = toHTMLFieldSetElement(ancestor); 121 break; 122 } 123 } 124 m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->isDisabledFormControl() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled; 125 } 126 127 void HTMLFormControlElement::ancestorDisabledStateWasChanged() 128 { 129 m_ancestorDisabledState = AncestorDisabledStateUnknown; 130 disabledAttributeChanged(); 131 } 132 133 void HTMLFormControlElement::reset() 134 { 135 setAutofilled(false); 136 resetImpl(); 137 } 138 139 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 140 { 141 if (name == formAttr) { 142 formAttributeChanged(); 143 UseCounter::count(document(), UseCounter::FormAttribute); 144 } else if (name == disabledAttr) { 145 bool oldDisabled = m_disabled; 146 m_disabled = !value.isNull(); 147 if (oldDisabled != m_disabled) 148 disabledAttributeChanged(); 149 } else if (name == readonlyAttr) { 150 bool wasReadOnly = m_isReadOnly; 151 m_isReadOnly = !value.isNull(); 152 if (wasReadOnly != m_isReadOnly) { 153 setNeedsWillValidateCheck(); 154 setNeedsStyleRecalc(SubtreeStyleChange); 155 if (renderer() && renderer()->style()->hasAppearance()) 156 RenderTheme::theme().stateChanged(renderer(), ReadOnlyControlState); 157 } 158 } else if (name == requiredAttr) { 159 bool wasRequired = m_isRequired; 160 m_isRequired = !value.isNull(); 161 if (wasRequired != m_isRequired) 162 requiredAttributeChanged(); 163 UseCounter::count(document(), UseCounter::RequiredAttribute); 164 } else if (name == autofocusAttr) { 165 HTMLElement::parseAttribute(name, value); 166 UseCounter::count(document(), UseCounter::AutoFocusAttribute); 167 } else 168 HTMLElement::parseAttribute(name, value); 169 } 170 171 void HTMLFormControlElement::disabledAttributeChanged() 172 { 173 setNeedsWillValidateCheck(); 174 pseudoStateChanged(CSSSelector::PseudoDisabled); 175 pseudoStateChanged(CSSSelector::PseudoEnabled); 176 if (renderer() && renderer()->style()->hasAppearance()) 177 RenderTheme::theme().stateChanged(renderer(), EnabledControlState); 178 if (isDisabledFormControl() && treeScope().adjustedFocusedElement() == this) { 179 // We might want to call blur(), but it's dangerous to dispatch events 180 // here. 181 document().setNeedsFocusedElementCheck(); 182 } 183 } 184 185 void HTMLFormControlElement::requiredAttributeChanged() 186 { 187 setNeedsValidityCheck(); 188 // Style recalculation is needed because style selectors may include 189 // :required and :optional pseudo-classes. 190 setNeedsStyleRecalc(SubtreeStyleChange); 191 } 192 193 bool HTMLFormControlElement::supportsAutofocus() const 194 { 195 return false; 196 } 197 198 bool HTMLFormControlElement::isAutofocusable() const 199 { 200 return fastHasAttribute(autofocusAttr) && supportsAutofocus(); 201 } 202 203 void HTMLFormControlElement::setAutofilled(bool autofilled) 204 { 205 if (autofilled == m_isAutofilled) 206 return; 207 208 m_isAutofilled = autofilled; 209 setNeedsStyleRecalc(SubtreeStyleChange); 210 } 211 212 static bool shouldAutofocusOnAttach(const HTMLFormControlElement* element) 213 { 214 if (!element->isAutofocusable()) 215 return false; 216 if (element->document().isSandboxed(SandboxAutomaticFeatures)) { 217 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 218 element->document().addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set.")); 219 return false; 220 } 221 222 return true; 223 } 224 225 void HTMLFormControlElement::attach(const AttachContext& context) 226 { 227 HTMLElement::attach(context); 228 229 if (!renderer()) 230 return; 231 232 // The call to updateFromElement() needs to go after the call through 233 // to the base class's attach() because that can sometimes do a close 234 // on the renderer. 235 renderer()->updateFromElement(); 236 237 // FIXME: Autofocus handling should be moved to insertedInto according to 238 // the standard. 239 if (shouldAutofocusOnAttach(this)) 240 document().setAutofocusElement(this); 241 } 242 243 void HTMLFormControlElement::didMoveToNewDocument(Document& oldDocument) 244 { 245 FormAssociatedElement::didMoveToNewDocument(oldDocument); 246 HTMLElement::didMoveToNewDocument(oldDocument); 247 } 248 249 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint) 250 { 251 m_ancestorDisabledState = AncestorDisabledStateUnknown; 252 m_dataListAncestorState = Unknown; 253 setNeedsWillValidateCheck(); 254 HTMLElement::insertedInto(insertionPoint); 255 FormAssociatedElement::insertedInto(insertionPoint); 256 return InsertionDone; 257 } 258 259 void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint) 260 { 261 hideVisibleValidationMessage(); 262 m_hasValidationMessage = false; 263 m_ancestorDisabledState = AncestorDisabledStateUnknown; 264 m_dataListAncestorState = Unknown; 265 HTMLElement::removedFrom(insertionPoint); 266 FormAssociatedElement::removedFrom(insertionPoint); 267 } 268 269 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed) 270 { 271 m_wasChangedSinceLastFormControlChangeEvent = changed; 272 } 273 274 void HTMLFormControlElement::dispatchChangeEvent() 275 { 276 dispatchScopedEvent(Event::createBubble(EventTypeNames::change)); 277 } 278 279 void HTMLFormControlElement::dispatchFormControlChangeEvent() 280 { 281 dispatchChangeEvent(); 282 setChangedSinceLastFormControlChangeEvent(false); 283 } 284 285 void HTMLFormControlElement::dispatchFormControlInputEvent() 286 { 287 setChangedSinceLastFormControlChangeEvent(true); 288 HTMLElement::dispatchInputEvent(); 289 } 290 291 HTMLFormElement* HTMLFormControlElement::formOwner() const 292 { 293 return FormAssociatedElement::form(); 294 } 295 296 bool HTMLFormControlElement::isDisabledFormControl() const 297 { 298 if (m_disabled) 299 return true; 300 301 if (m_ancestorDisabledState == AncestorDisabledStateUnknown) 302 updateAncestorDisabledState(); 303 return m_ancestorDisabledState == AncestorDisabledStateDisabled; 304 } 305 306 bool HTMLFormControlElement::isRequired() const 307 { 308 return m_isRequired; 309 } 310 311 String HTMLFormControlElement::resultForDialogSubmit() 312 { 313 return fastGetAttribute(valueAttr); 314 } 315 316 void HTMLFormControlElement::didRecalcStyle(StyleRecalcChange) 317 { 318 if (RenderObject* renderer = this->renderer()) 319 renderer->updateFromElement(); 320 } 321 322 bool HTMLFormControlElement::supportsFocus() const 323 { 324 return !isDisabledFormControl(); 325 } 326 327 bool HTMLFormControlElement::isKeyboardFocusable() const 328 { 329 // Skip tabIndex check in a parent class. 330 return isFocusable(); 331 } 332 333 bool HTMLFormControlElement::shouldShowFocusRingOnMouseFocus() const 334 { 335 return false; 336 } 337 338 bool HTMLFormControlElement::shouldHaveFocusAppearance() const 339 { 340 return !m_wasFocusedByMouse || shouldShowFocusRingOnMouseFocus(); 341 } 342 343 void HTMLFormControlElement::dispatchFocusEvent(Element* oldFocusedElement, FocusType type) 344 { 345 if (type != FocusTypePage) 346 m_wasFocusedByMouse = type == FocusTypeMouse; 347 HTMLElement::dispatchFocusEvent(oldFocusedElement, type); 348 } 349 350 void HTMLFormControlElement::willCallDefaultEventHandler(const Event& event) 351 { 352 if (!m_wasFocusedByMouse) 353 return; 354 if (!event.isKeyboardEvent() || event.type() != EventTypeNames::keydown) 355 return; 356 m_wasFocusedByMouse = false; 357 if (renderer()) 358 renderer()->setShouldDoFullPaintInvalidation(true); 359 } 360 361 short HTMLFormControlElement::tabIndex() const 362 { 363 // Skip the supportsFocus check in HTMLElement. 364 return Element::tabIndex(); 365 } 366 367 bool HTMLFormControlElement::recalcWillValidate() const 368 { 369 if (m_dataListAncestorState == Unknown) { 370 if (Traversal<HTMLDataListElement>::firstAncestor(*this)) 371 m_dataListAncestorState = InsideDataList; 372 else 373 m_dataListAncestorState = NotInsideDataList; 374 } 375 return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly(); 376 } 377 378 bool HTMLFormControlElement::willValidate() const 379 { 380 if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) { 381 m_willValidateInitialized = true; 382 bool newWillValidate = recalcWillValidate(); 383 if (m_willValidate != newWillValidate) { 384 m_willValidate = newWillValidate; 385 const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck(); 386 } 387 } else { 388 // If the following assertion fails, setNeedsWillValidateCheck() is not 389 // called correctly when something which changes recalcWillValidate() result 390 // is updated. 391 ASSERT(m_willValidate == recalcWillValidate()); 392 } 393 return m_willValidate; 394 } 395 396 void HTMLFormControlElement::setNeedsWillValidateCheck() 397 { 398 // We need to recalculate willValidate immediately because willValidate change can causes style change. 399 bool newWillValidate = recalcWillValidate(); 400 if (m_willValidateInitialized && m_willValidate == newWillValidate) 401 return; 402 m_willValidateInitialized = true; 403 m_willValidate = newWillValidate; 404 setNeedsValidityCheck(); 405 setNeedsStyleRecalc(SubtreeStyleChange); 406 if (!m_willValidate) 407 hideVisibleValidationMessage(); 408 } 409 410 void HTMLFormControlElement::findCustomValidationMessageTextDirection(const String& message, TextDirection &messageDir, String& subMessage, TextDirection &subMessageDir) 411 { 412 bool hasStrongDirection; 413 subMessage = fastGetAttribute(titleAttr); 414 messageDir = determineDirectionality(message, hasStrongDirection); 415 if (!subMessage.isEmpty()) 416 subMessageDir = renderer()->style()->direction(); 417 } 418 419 void HTMLFormControlElement::updateVisibleValidationMessage() 420 { 421 Page* page = document().page(); 422 if (!page) 423 return; 424 String message; 425 if (renderer() && willValidate()) 426 message = validationMessage().stripWhiteSpace(); 427 428 m_hasValidationMessage = true; 429 ValidationMessageClient* client = &page->validationMessageClient(); 430 TextDirection messageDir = LTR; 431 TextDirection subMessageDir = LTR; 432 String subMessage = String(); 433 if (message.isEmpty()) 434 client->hideValidationMessage(*this); 435 else 436 findCustomValidationMessageTextDirection(message, messageDir, subMessage, subMessageDir); 437 client->showValidationMessage(*this, message, messageDir, subMessage, subMessageDir); 438 } 439 440 void HTMLFormControlElement::hideVisibleValidationMessage() 441 { 442 if (!m_hasValidationMessage) 443 return; 444 445 if (ValidationMessageClient* client = validationMessageClient()) 446 client->hideValidationMessage(*this); 447 } 448 449 bool HTMLFormControlElement::isValidationMessageVisible() const 450 { 451 if (!m_hasValidationMessage) 452 return false; 453 454 ValidationMessageClient* client = validationMessageClient(); 455 if (!client) 456 return false; 457 458 return client->isValidationMessageVisible(*this); 459 } 460 461 ValidationMessageClient* HTMLFormControlElement::validationMessageClient() const 462 { 463 Page* page = document().page(); 464 if (!page) 465 return 0; 466 467 return &page->validationMessageClient(); 468 } 469 470 bool HTMLFormControlElement::checkValidity(WillBeHeapVector<RefPtrWillBeMember<FormAssociatedElement> >* unhandledInvalidControls) 471 { 472 if (!willValidate() || isValidFormControlElement()) 473 return true; 474 // An event handler can deref this object. 475 RefPtrWillBeRawPtr<HTMLFormControlElement> protector(this); 476 RefPtrWillBeRawPtr<Document> originalDocument(document()); 477 bool needsDefaultAction = dispatchEvent(Event::createCancelable(EventTypeNames::invalid)); 478 if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document()) 479 unhandledInvalidControls->append(this); 480 return false; 481 } 482 483 bool HTMLFormControlElement::isValidFormControlElement() 484 { 485 // If the following assertion fails, setNeedsValidityCheck() is not called 486 // correctly when something which changes validity is updated. 487 ASSERT(m_isValid == valid()); 488 return m_isValid; 489 } 490 491 void HTMLFormControlElement::setNeedsValidityCheck() 492 { 493 bool newIsValid = valid(); 494 if (willValidate() && newIsValid != m_isValid) { 495 // Update style for pseudo classes such as :valid :invalid. 496 setNeedsStyleRecalc(SubtreeStyleChange); 497 } 498 m_isValid = newIsValid; 499 500 // Updates only if this control already has a validation message. 501 if (isValidationMessageVisible()) { 502 // Calls updateVisibleValidationMessage() even if m_isValid is not 503 // changed because a validation message can be changed. 504 updateVisibleValidationMessage(); 505 } 506 } 507 508 void HTMLFormControlElement::setCustomValidity(const String& error) 509 { 510 FormAssociatedElement::setCustomValidity(error); 511 setNeedsValidityCheck(); 512 } 513 514 void HTMLFormControlElement::dispatchBlurEvent(Element* newFocusedElement) 515 { 516 HTMLElement::dispatchBlurEvent(newFocusedElement); 517 hideVisibleValidationMessage(); 518 } 519 520 bool HTMLFormControlElement::isSuccessfulSubmitButton() const 521 { 522 return canBeSuccessfulSubmitButton() && !isDisabledFormControl(); 523 } 524 525 bool HTMLFormControlElement::isDefaultButtonForForm() const 526 { 527 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this; 528 } 529 530 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node) 531 { 532 if (!node) 533 return 0; 534 return Traversal<HTMLFormControlElement>::firstAncestorOrSelf(*node); 535 } 536 537 String HTMLFormControlElement::nameForAutofill() const 538 { 539 String fullName = name(); 540 String trimmedName = fullName.stripWhiteSpace(); 541 if (!trimmedName.isEmpty()) 542 return trimmedName; 543 fullName = getIdAttribute(); 544 trimmedName = fullName.stripWhiteSpace(); 545 return trimmedName; 546 } 547 548 void HTMLFormControlElement::setFocus(bool flag) 549 { 550 LabelableElement::setFocus(flag); 551 552 if (!flag && wasChangedSinceLastFormControlChangeEvent()) 553 dispatchFormControlChangeEvent(); 554 } 555 556 } // namespace blink 557