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