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