1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap@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 "ElementShadow.h" 30#include "Event.h" 31#include "EventHandler.h" 32#include "EventNames.h" 33#include "FeatureObserver.h" 34#include "Frame.h" 35#include "HTMLFieldSetElement.h" 36#include "HTMLFormElement.h" 37#include "HTMLInputElement.h" 38#include "HTMLLegendElement.h" 39#include "RenderBox.h" 40#include "RenderTheme.h" 41#include "ScriptEventListener.h" 42#include "ValidationMessage.h" 43#include "ValidityState.h" 44#include <wtf/Vector.h> 45 46namespace WebCore { 47 48using namespace HTMLNames; 49using namespace std; 50 51HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) 52 : LabelableElement(tagName, document) 53 , m_disabled(false) 54 , m_isReadOnly(false) 55 , m_isRequired(false) 56 , m_valueMatchesRenderer(false) 57 , m_ancestorDisabledState(AncestorDisabledStateUnknown) 58 , m_dataListAncestorState(Unknown) 59 , m_willValidateInitialized(false) 60 , m_willValidate(true) 61 , m_isValid(true) 62 , m_wasChangedSinceLastFormControlChangeEvent(false) 63 , m_hasAutofocused(false) 64{ 65 setForm(form ? form : findFormAncestor()); 66 setHasCustomStyleCallbacks(); 67} 68 69HTMLFormControlElement::~HTMLFormControlElement() 70{ 71} 72 73String 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 81void HTMLFormControlElement::setFormEnctype(const String& value) 82{ 83 setAttribute(formenctypeAttr, value); 84} 85 86String 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 94void HTMLFormControlElement::setFormMethod(const String& value) 95{ 96 setAttribute(formmethodAttr, value); 97} 98 99bool HTMLFormControlElement::formNoValidate() const 100{ 101 return fastHasAttribute(formnovalidateAttr); 102} 103 104void 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 = static_cast<HTMLFieldSetElement*>(ancestor); 113 break; 114 } 115 } 116 m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->isDisabledFormControl() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled; 117} 118 119void HTMLFormControlElement::ancestorDisabledStateWasChanged() 120{ 121 m_ancestorDisabledState = AncestorDisabledStateUnknown; 122 disabledAttributeChanged(); 123} 124 125void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 126{ 127 if (name == formAttr) { 128 formAttributeChanged(); 129 FeatureObserver::observe(document(), FeatureObserver::FormAttribute); 130 } else if (name == disabledAttr) { 131 bool oldDisabled = m_disabled; 132 m_disabled = !value.isNull(); 133 if (oldDisabled != m_disabled) 134 disabledAttributeChanged(); 135 } else if (name == readonlyAttr) { 136 bool wasReadOnly = m_isReadOnly; 137 m_isReadOnly = !value.isNull(); 138 if (wasReadOnly != m_isReadOnly) { 139 setNeedsWillValidateCheck(); 140 setNeedsStyleRecalc(); 141 if (renderer() && renderer()->style()->hasAppearance()) 142 renderer()->theme()->stateChanged(renderer(), ReadOnlyState); 143 } 144 } else if (name == requiredAttr) { 145 bool wasRequired = m_isRequired; 146 m_isRequired = !value.isNull(); 147 if (wasRequired != m_isRequired) 148 requiredAttributeChanged(); 149 FeatureObserver::observe(document(), FeatureObserver::RequiredAttribute); 150 } else if (name == autofocusAttr) { 151 HTMLElement::parseAttribute(name, value); 152 FeatureObserver::observe(document(), FeatureObserver::AutoFocusAttribute); 153 } else 154 HTMLElement::parseAttribute(name, value); 155} 156 157void HTMLFormControlElement::disabledAttributeChanged() 158{ 159 setNeedsWillValidateCheck(); 160 didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled); 161 if (renderer() && renderer()->style()->hasAppearance()) 162 renderer()->theme()->stateChanged(renderer(), EnabledState); 163} 164 165void HTMLFormControlElement::requiredAttributeChanged() 166{ 167 setNeedsValidityCheck(); 168 // Style recalculation is needed because style selectors may include 169 // :required and :optional pseudo-classes. 170 setNeedsStyleRecalc(); 171} 172 173static bool shouldAutofocus(HTMLFormControlElement* element) 174{ 175 if (!element->fastHasAttribute(autofocusAttr)) 176 return false; 177 if (!element->renderer()) 178 return false; 179 if (element->document()->ignoreAutofocus()) 180 return false; 181 if (element->document()->isSandboxed(SandboxAutomaticFeatures)) { 182 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. 183 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."); 184 return false; 185 } 186 if (element->hasAutofocused()) 187 return false; 188 189 // FIXME: Should this set of hasTagName checks be replaced by a 190 // virtual member function? 191 if (element->hasTagName(inputTag)) 192 return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden(); 193 if (element->hasTagName(selectTag)) 194 return true; 195 if (element->hasTagName(keygenTag)) 196 return true; 197 if (element->hasTagName(buttonTag)) 198 return true; 199 if (element->hasTagName(textareaTag)) 200 return true; 201 202 return false; 203} 204 205static void focusPostAttach(Node* element, unsigned) 206{ 207 toElement(element)->focus(); 208 element->deref(); 209} 210 211void HTMLFormControlElement::attach(const AttachContext& context) 212{ 213 PostAttachCallbackDisabler disabler(this); 214 215 HTMLElement::attach(context); 216 217 // The call to updateFromElement() needs to go after the call through 218 // to the base class's attach() because that can sometimes do a close 219 // on the renderer. 220 if (renderer()) 221 renderer()->updateFromElement(); 222 223 if (shouldAutofocus(this)) { 224 setAutofocused(); 225 ref(); 226 queuePostAttachCallback(focusPostAttach, this); 227 } 228} 229 230void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument) 231{ 232 FormAssociatedElement::didMoveToNewDocument(oldDocument); 233 HTMLElement::didMoveToNewDocument(oldDocument); 234} 235 236Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint) 237{ 238 m_ancestorDisabledState = AncestorDisabledStateUnknown; 239 m_dataListAncestorState = Unknown; 240 setNeedsWillValidateCheck(); 241 HTMLElement::insertedInto(insertionPoint); 242 FormAssociatedElement::insertedInto(insertionPoint); 243 return InsertionDone; 244} 245 246void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint) 247{ 248 m_validationMessage = nullptr; 249 m_ancestorDisabledState = AncestorDisabledStateUnknown; 250 m_dataListAncestorState = Unknown; 251 HTMLElement::removedFrom(insertionPoint); 252 FormAssociatedElement::removedFrom(insertionPoint); 253} 254 255void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed) 256{ 257 m_wasChangedSinceLastFormControlChangeEvent = changed; 258} 259 260void HTMLFormControlElement::dispatchChangeEvent() 261{ 262 dispatchScopedEvent(Event::create(eventNames().changeEvent, true, false)); 263} 264 265void HTMLFormControlElement::dispatchFormControlChangeEvent() 266{ 267 dispatchChangeEvent(); 268 setChangedSinceLastFormControlChangeEvent(false); 269} 270 271void HTMLFormControlElement::dispatchFormControlInputEvent() 272{ 273 setChangedSinceLastFormControlChangeEvent(true); 274 HTMLElement::dispatchInputEvent(); 275} 276 277bool HTMLFormControlElement::isDisabledFormControl() const 278{ 279 if (m_disabled) 280 return true; 281 282 if (m_ancestorDisabledState == AncestorDisabledStateUnknown) 283 updateAncestorDisabledState(); 284 if (m_ancestorDisabledState == AncestorDisabledStateDisabled) 285 return true; 286 return HTMLElement::isDisabledFormControl(); 287} 288 289bool HTMLFormControlElement::isRequired() const 290{ 291 return m_isRequired; 292} 293 294static void updateFromElementCallback(Node* node, unsigned) 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 302void 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 310bool HTMLFormControlElement::supportsFocus() const 311{ 312 return !isDisabledFormControl(); 313} 314 315bool HTMLFormControlElement::isFocusable() 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 Node::isFocusable). 319 if (renderer() && (!renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())) 320 return false; 321 // HTMLElement::isFocusable handles visibility and calls suportsFocus which 322 // will cover the disabled case. 323 return HTMLElement::isFocusable(); 324} 325 326bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const 327{ 328 if (isFocusable()) 329 if (document()->frame()) 330 return document()->frame()->eventHandler()->tabsToAllFormControls(event); 331 return false; 332} 333 334bool HTMLFormControlElement::isMouseFocusable() const 335{ 336#if PLATFORM(GTK) || PLATFORM(QT) 337 return HTMLElement::isMouseFocusable(); 338#else 339 return false; 340#endif 341} 342 343short HTMLFormControlElement::tabIndex() const 344{ 345 // Skip the supportsFocus check in HTMLElement. 346 return Element::tabIndex(); 347} 348 349bool HTMLFormControlElement::recalcWillValidate() const 350{ 351 if (m_dataListAncestorState == Unknown) { 352 for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { 353 if (ancestor->hasTagName(datalistTag)) { 354 m_dataListAncestorState = InsideDataList; 355 break; 356 } 357 } 358 if (m_dataListAncestorState == Unknown) 359 m_dataListAncestorState = NotInsideDataList; 360 } 361 return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly(); 362} 363 364bool HTMLFormControlElement::willValidate() const 365{ 366 if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) { 367 m_willValidateInitialized = true; 368 bool newWillValidate = recalcWillValidate(); 369 if (m_willValidate != newWillValidate) { 370 m_willValidate = newWillValidate; 371 const_cast<HTMLFormControlElement*>(this)->setNeedsValidityCheck(); 372 } 373 } else { 374 // If the following assertion fails, setNeedsWillValidateCheck() is not 375 // called correctly when something which changes recalcWillValidate() result 376 // is updated. 377 ASSERT(m_willValidate == recalcWillValidate()); 378 } 379 return m_willValidate; 380} 381 382void HTMLFormControlElement::setNeedsWillValidateCheck() 383{ 384 // We need to recalculate willValidate immediately because willValidate change can causes style change. 385 bool newWillValidate = recalcWillValidate(); 386 if (m_willValidateInitialized && m_willValidate == newWillValidate) 387 return; 388 m_willValidateInitialized = true; 389 m_willValidate = newWillValidate; 390 setNeedsValidityCheck(); 391 setNeedsStyleRecalc(); 392 if (!m_willValidate) 393 hideVisibleValidationMessage(); 394} 395 396void HTMLFormControlElement::updateVisibleValidationMessage() 397{ 398 Page* page = document()->page(); 399 if (!page) 400 return; 401 String message; 402 if (renderer() && willValidate()) 403 message = validationMessage().stripWhiteSpace(); 404 if (!m_validationMessage) 405 m_validationMessage = ValidationMessage::create(this); 406 m_validationMessage->updateValidationMessage(message); 407} 408 409void HTMLFormControlElement::hideVisibleValidationMessage() 410{ 411 if (m_validationMessage) 412 m_validationMessage->requestToHideMessage(); 413} 414 415bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls) 416{ 417 if (!willValidate() || isValidFormControlElement()) 418 return true; 419 // An event handler can deref this object. 420 RefPtr<HTMLFormControlElement> protector(this); 421 RefPtr<Document> originalDocument(document()); 422 bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true)); 423 if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document()) 424 unhandledInvalidControls->append(this); 425 return false; 426} 427 428bool HTMLFormControlElement::isValidFormControlElement() 429{ 430 // If the following assertion fails, setNeedsValidityCheck() is not called 431 // correctly when something which changes validity is updated. 432 ASSERT(m_isValid == validity()->valid()); 433 return m_isValid; 434} 435 436void HTMLFormControlElement::setNeedsValidityCheck() 437{ 438 bool newIsValid = validity()->valid(); 439 if (willValidate() && newIsValid != m_isValid) { 440 // Update style for pseudo classes such as :valid :invalid. 441 setNeedsStyleRecalc(); 442 } 443 m_isValid = newIsValid; 444 445 // Updates only if this control already has a validtion message. 446 if (m_validationMessage && m_validationMessage->isVisible()) { 447 // Calls updateVisibleValidationMessage() even if m_isValid is not 448 // changed because a validation message can be chagned. 449 updateVisibleValidationMessage(); 450 } 451} 452 453void HTMLFormControlElement::setCustomValidity(const String& error) 454{ 455 FormAssociatedElement::setCustomValidity(error); 456 setNeedsValidityCheck(); 457} 458 459bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const 460{ 461 return m_validationMessage && m_validationMessage->shadowTreeContains(node); 462} 463 464void HTMLFormControlElement::dispatchBlurEvent(PassRefPtr<Element> newFocusedElement) 465{ 466 HTMLElement::dispatchBlurEvent(newFocusedElement); 467 hideVisibleValidationMessage(); 468} 469 470HTMLFormElement* HTMLFormControlElement::virtualForm() const 471{ 472 return FormAssociatedElement::form(); 473} 474 475bool HTMLFormControlElement::isDefaultButtonForForm() const 476{ 477 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this; 478} 479 480HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node) 481{ 482 for (; node; node = node->parentNode()) { 483 if (node->isElementNode() && toElement(node)->isFormControlElement()) 484 return static_cast<HTMLFormControlElement*>(node); 485 } 486 return 0; 487} 488 489} // namespace Webcore 490