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