Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / html / HTMLFormControlElement.cpp
blob54d22d6795a6220ec8c75e90eb70ab7ad54e55d4
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)
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.
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.
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.
25 #include "config.h"
26 #include "core/html/HTMLFormControlElement.h"
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/html/parser/HTMLParserIdioms.h"
38 #include "core/inspector/ConsoleMessage.h"
39 #include "core/layout/LayoutBox.h"
40 #include "core/layout/LayoutTheme.h"
41 #include "core/page/Page.h"
42 #include "core/page/ValidationMessageClient.h"
43 #include "platform/text/BidiTextRun.h"
44 #include "wtf/Vector.h"
46 namespace blink {
48 using namespace HTMLNames;
50 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
51 : LabelableElement(tagName, document)
52 , m_disabled(false)
53 , m_isAutofilled(false)
54 , m_isReadOnly(false)
55 , m_isRequired(false)
56 , m_hasValidationMessage(false)
57 , m_ancestorDisabledState(AncestorDisabledStateUnknown)
58 , m_dataListAncestorState(Unknown)
59 , m_willValidateInitialized(false)
60 , m_willValidate(true)
61 , m_isValid(true)
62 , m_validityIsDirty(false)
63 , m_wasChangedSinceLastFormControlChangeEvent(false)
64 , m_wasFocusedByMouse(false)
66 setHasCustomStyleCallbacks();
67 associateByParser(form);
70 HTMLFormControlElement::~HTMLFormControlElement()
72 #if !ENABLE(OILPAN)
73 #if ENABLE(ASSERT)
74 // Recalculate m_willValidate and m_isValid for the vtbl change in order to
75 // avoid assertion failures in isValidElement() called in setForm(0).
76 setNeedsWillValidateCheck();
77 setNeedsValidityCheck();
78 #endif
79 setForm(0);
80 #endif
83 DEFINE_TRACE(HTMLFormControlElement)
85 FormAssociatedElement::trace(visitor);
86 LabelableElement::trace(visitor);
89 String HTMLFormControlElement::formAction() const
91 const AtomicString& action = fastGetAttribute(formactionAttr);
92 if (action.isEmpty())
93 return document().url();
94 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(action));
97 void HTMLFormControlElement::setFormAction(const AtomicString& value)
99 setAttribute(formactionAttr, value);
102 String HTMLFormControlElement::formEnctype() const
104 const AtomicString& formEnctypeAttr = fastGetAttribute(formenctypeAttr);
105 if (formEnctypeAttr.isNull())
106 return emptyString();
107 return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr);
110 void HTMLFormControlElement::setFormEnctype(const AtomicString& value)
112 setAttribute(formenctypeAttr, value);
115 String HTMLFormControlElement::formMethod() const
117 const AtomicString& formMethodAttr = fastGetAttribute(formmethodAttr);
118 if (formMethodAttr.isNull())
119 return emptyString();
120 return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr));
123 void HTMLFormControlElement::setFormMethod(const AtomicString& value)
125 setAttribute(formmethodAttr, value);
128 bool HTMLFormControlElement::formNoValidate() const
130 return fastHasAttribute(formnovalidateAttr);
133 void HTMLFormControlElement::updateAncestorDisabledState() const
135 HTMLFieldSetElement* fieldSetAncestor = 0;
136 ContainerNode* legendAncestor = 0;
137 for (HTMLElement* ancestor = Traversal<HTMLElement>::firstAncestor(*this); ancestor; ancestor = Traversal<HTMLElement>::firstAncestor(*ancestor)) {
138 if (!legendAncestor && isHTMLLegendElement(*ancestor))
139 legendAncestor = ancestor;
140 if (isHTMLFieldSetElement(*ancestor)) {
141 fieldSetAncestor = toHTMLFieldSetElement(ancestor);
142 break;
145 m_ancestorDisabledState = (fieldSetAncestor && fieldSetAncestor->isDisabledFormControl() && !(legendAncestor && legendAncestor == fieldSetAncestor->legend())) ? AncestorDisabledStateDisabled : AncestorDisabledStateEnabled;
148 void HTMLFormControlElement::ancestorDisabledStateWasChanged()
150 m_ancestorDisabledState = AncestorDisabledStateUnknown;
151 disabledAttributeChanged();
154 void HTMLFormControlElement::reset()
156 setAutofilled(false);
157 resetImpl();
160 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
162 if (name == formAttr) {
163 formAttributeChanged();
164 UseCounter::count(document(), UseCounter::FormAttribute);
165 } else if (name == disabledAttr) {
166 bool oldDisabled = m_disabled;
167 m_disabled = !value.isNull();
168 if (oldDisabled != m_disabled)
169 disabledAttributeChanged();
170 } else if (name == readonlyAttr) {
171 bool wasReadOnly = m_isReadOnly;
172 m_isReadOnly = !value.isNull();
173 if (wasReadOnly != m_isReadOnly) {
174 setNeedsWillValidateCheck();
175 setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::fromAttribute(name));
176 if (layoutObject())
177 LayoutTheme::theme().controlStateChanged(*layoutObject(), ReadOnlyControlState);
179 } else if (name == requiredAttr) {
180 bool wasRequired = m_isRequired;
181 m_isRequired = !value.isNull();
182 if (wasRequired != m_isRequired)
183 requiredAttributeChanged();
184 UseCounter::count(document(), UseCounter::RequiredAttribute);
185 } else if (name == autofocusAttr) {
186 HTMLElement::parseAttribute(name, value);
187 UseCounter::count(document(), UseCounter::AutoFocusAttribute);
188 } else {
189 HTMLElement::parseAttribute(name, value);
193 void HTMLFormControlElement::disabledAttributeChanged()
195 setNeedsWillValidateCheck();
196 pseudoStateChanged(CSSSelector::PseudoDisabled);
197 pseudoStateChanged(CSSSelector::PseudoEnabled);
198 if (layoutObject())
199 LayoutTheme::theme().controlStateChanged(*layoutObject(), EnabledControlState);
200 if (isDisabledFormControl() && treeScope().adjustedFocusedElement() == this) {
201 // We might want to call blur(), but it's dangerous to dispatch events
202 // here.
203 document().setNeedsFocusedElementCheck();
207 void HTMLFormControlElement::requiredAttributeChanged()
209 setNeedsValidityCheck();
210 pseudoStateChanged(CSSSelector::PseudoRequired);
211 pseudoStateChanged(CSSSelector::PseudoOptional);
214 bool HTMLFormControlElement::supportsAutofocus() const
216 return false;
219 bool HTMLFormControlElement::isAutofocusable() const
221 return fastHasAttribute(autofocusAttr) && supportsAutofocus();
224 void HTMLFormControlElement::setAutofilled(bool autofilled)
226 if (autofilled == m_isAutofilled)
227 return;
229 m_isAutofilled = autofilled;
230 pseudoStateChanged(CSSSelector::PseudoAutofill);
233 static bool shouldAutofocusOnAttach(const HTMLFormControlElement* element)
235 if (!element->isAutofocusable())
236 return false;
237 if (element->document().isSandboxed(SandboxAutomaticFeatures)) {
238 // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
239 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."));
240 return false;
243 return true;
246 void HTMLFormControlElement::attach(const AttachContext& context)
248 HTMLElement::attach(context);
250 if (!layoutObject())
251 return;
253 // The call to updateFromElement() needs to go after the call through
254 // to the base class's attach() because that can sometimes do a close
255 // on the layoutObject.
256 layoutObject()->updateFromElement();
258 // FIXME: Autofocus handling should be moved to insertedInto according to
259 // the standard.
260 if (shouldAutofocusOnAttach(this))
261 document().setAutofocusElement(this);
264 void HTMLFormControlElement::didMoveToNewDocument(Document& oldDocument)
266 FormAssociatedElement::didMoveToNewDocument(oldDocument);
267 HTMLElement::didMoveToNewDocument(oldDocument);
270 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode* insertionPoint)
272 m_ancestorDisabledState = AncestorDisabledStateUnknown;
273 m_dataListAncestorState = Unknown;
274 setNeedsWillValidateCheck();
275 HTMLElement::insertedInto(insertionPoint);
276 FormAssociatedElement::insertedInto(insertionPoint);
277 fieldSetAncestorsSetNeedsValidityCheck(insertionPoint);
279 // Trigger for elements outside of forms.
280 if (!formOwner() && insertionPoint->inDocument())
281 document().didAssociateFormControl(this);
283 return InsertionDone;
286 void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
288 fieldSetAncestorsSetNeedsValidityCheck(insertionPoint);
289 hideVisibleValidationMessage();
290 m_hasValidationMessage = false;
291 m_ancestorDisabledState = AncestorDisabledStateUnknown;
292 m_dataListAncestorState = Unknown;
293 setNeedsWillValidateCheck();
294 HTMLElement::removedFrom(insertionPoint);
295 FormAssociatedElement::removedFrom(insertionPoint);
296 document().removeFormAssociation(this);
299 void HTMLFormControlElement::willChangeForm()
301 FormAssociatedElement::willChangeForm();
302 formOwnerSetNeedsValidityCheck();
305 void HTMLFormControlElement::didChangeForm()
307 FormAssociatedElement::didChangeForm();
308 formOwnerSetNeedsValidityCheck();
311 void HTMLFormControlElement::formOwnerSetNeedsValidityCheck()
313 if (HTMLFormElement* form = formOwner()) {
314 form->pseudoStateChanged(CSSSelector::PseudoValid);
315 form->pseudoStateChanged(CSSSelector::PseudoInvalid);
319 void HTMLFormControlElement::fieldSetAncestorsSetNeedsValidityCheck(Node* node)
321 if (!node)
322 return;
323 for (HTMLFieldSetElement* fieldSet = Traversal<HTMLFieldSetElement>::firstAncestorOrSelf(*node); fieldSet; fieldSet = Traversal<HTMLFieldSetElement>::firstAncestor(*fieldSet)) {
324 fieldSet->pseudoStateChanged(CSSSelector::PseudoValid);
325 fieldSet->pseudoStateChanged(CSSSelector::PseudoInvalid);
329 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
331 m_wasChangedSinceLastFormControlChangeEvent = changed;
334 void HTMLFormControlElement::dispatchChangeEvent()
336 dispatchScopedEvent(Event::createBubble(EventTypeNames::change));
339 void HTMLFormControlElement::dispatchFormControlChangeEvent()
341 dispatchChangeEvent();
342 setChangedSinceLastFormControlChangeEvent(false);
345 void HTMLFormControlElement::dispatchFormControlInputEvent()
347 setChangedSinceLastFormControlChangeEvent(true);
348 HTMLElement::dispatchInputEvent();
351 HTMLFormElement* HTMLFormControlElement::formOwner() const
353 return FormAssociatedElement::form();
356 bool HTMLFormControlElement::isDisabledFormControl() const
358 if (m_disabled)
359 return true;
361 if (m_ancestorDisabledState == AncestorDisabledStateUnknown)
362 updateAncestorDisabledState();
363 return m_ancestorDisabledState == AncestorDisabledStateDisabled;
366 bool HTMLFormControlElement::isRequired() const
368 return m_isRequired;
371 String HTMLFormControlElement::resultForDialogSubmit()
373 return fastGetAttribute(valueAttr);
376 void HTMLFormControlElement::didRecalcStyle(StyleRecalcChange)
378 if (LayoutObject* layoutObject = this->layoutObject())
379 layoutObject->updateFromElement();
382 bool HTMLFormControlElement::supportsFocus() const
384 return !isDisabledFormControl();
387 bool HTMLFormControlElement::isKeyboardFocusable() const
389 // Skip tabIndex check in a parent class.
390 return isFocusable();
393 bool HTMLFormControlElement::shouldShowFocusRingOnMouseFocus() const
395 return false;
398 bool HTMLFormControlElement::shouldHaveFocusAppearance() const
400 return !m_wasFocusedByMouse || shouldShowFocusRingOnMouseFocus();
403 void HTMLFormControlElement::dispatchFocusEvent(Element* oldFocusedElement, WebFocusType type, InputDeviceCapabilities* sourceCapabilities)
405 if (type != WebFocusTypePage)
406 m_wasFocusedByMouse = type == WebFocusTypeMouse;
407 // ContainerNode::handleStyleChangeOnFocusStateChange() will inform LayoutTheme about the focus state change.
408 HTMLElement::dispatchFocusEvent(oldFocusedElement, type, sourceCapabilities);
411 void HTMLFormControlElement::willCallDefaultEventHandler(const Event& event)
413 if (!m_wasFocusedByMouse)
414 return;
415 if (!event.isKeyboardEvent() || event.type() != EventTypeNames::keydown)
416 return;
418 bool oldShouldHaveFocusAppearance = shouldHaveFocusAppearance();
419 m_wasFocusedByMouse = false;
421 // Change of m_wasFocusByMouse may affect shouldHaveFocusAppearance() and LayoutTheme::isFocused().
422 // Inform LayoutTheme if shouldHaveFocusAppearance() changes.
423 if (oldShouldHaveFocusAppearance != shouldHaveFocusAppearance() && layoutObject())
424 LayoutTheme::theme().controlStateChanged(*layoutObject(), FocusControlState);
427 short HTMLFormControlElement::tabIndex() const
429 // Skip the supportsFocus check in HTMLElement.
430 return Element::tabIndex();
433 bool HTMLFormControlElement::recalcWillValidate() const
435 if (m_dataListAncestorState == Unknown) {
436 if (Traversal<HTMLDataListElement>::firstAncestor(*this))
437 m_dataListAncestorState = InsideDataList;
438 else
439 m_dataListAncestorState = NotInsideDataList;
441 return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
444 bool HTMLFormControlElement::willValidate() const
446 if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
447 const_cast<HTMLFormControlElement*>(this)->setNeedsWillValidateCheck();
448 } else {
449 // If the following assertion fails, setNeedsWillValidateCheck() is not
450 // called correctly when something which changes recalcWillValidate() result
451 // is updated.
452 ASSERT(m_willValidate == recalcWillValidate());
454 return m_willValidate;
457 void HTMLFormControlElement::setNeedsWillValidateCheck()
459 // We need to recalculate willValidate immediately because willValidate change can causes style change.
460 bool newWillValidate = recalcWillValidate();
461 if (m_willValidateInitialized && m_willValidate == newWillValidate)
462 return;
463 m_willValidateInitialized = true;
464 m_willValidate = newWillValidate;
465 setNeedsValidityCheck();
466 // No need to trigger style recalculation here because
467 // setNeedsValidityCheck() does it in the right away. This relies on
468 // the assumption that valid() is always true if willValidate() is false.
470 if (!m_willValidate)
471 hideVisibleValidationMessage();
474 void HTMLFormControlElement::findCustomValidationMessageTextDirection(const String& message, TextDirection &messageDir, String& subMessage, TextDirection &subMessageDir)
476 subMessage = fastGetAttribute(titleAttr);
477 messageDir = determineDirectionality(message);
478 if (!subMessage.isEmpty())
479 subMessageDir = layoutObject()->style()->direction();
482 void HTMLFormControlElement::updateVisibleValidationMessage()
484 Page* page = document().page();
485 if (!page)
486 return;
487 String message;
488 if (layoutObject() && willValidate())
489 message = validationMessage().stripWhiteSpace();
491 m_hasValidationMessage = true;
492 ValidationMessageClient* client = &page->validationMessageClient();
493 TextDirection messageDir = LTR;
494 TextDirection subMessageDir = LTR;
495 String subMessage = String();
496 if (message.isEmpty())
497 client->hideValidationMessage(*this);
498 else
499 findCustomValidationMessageTextDirection(message, messageDir, subMessage, subMessageDir);
500 client->showValidationMessage(*this, message, messageDir, subMessage, subMessageDir);
503 void HTMLFormControlElement::hideVisibleValidationMessage()
505 if (!m_hasValidationMessage)
506 return;
508 if (ValidationMessageClient* client = validationMessageClient())
509 client->hideValidationMessage(*this);
512 bool HTMLFormControlElement::isValidationMessageVisible() const
514 if (!m_hasValidationMessage)
515 return false;
517 ValidationMessageClient* client = validationMessageClient();
518 if (!client)
519 return false;
521 return client->isValidationMessageVisible(*this);
524 ValidationMessageClient* HTMLFormControlElement::validationMessageClient() const
526 Page* page = document().page();
527 if (!page)
528 return nullptr;
530 return &page->validationMessageClient();
533 bool HTMLFormControlElement::checkValidity(WillBeHeapVector<RefPtrWillBeMember<HTMLFormControlElement>>* unhandledInvalidControls, CheckValidityEventBehavior eventBehavior)
535 if (isValidElement())
536 return true;
537 if (eventBehavior != CheckValidityDispatchInvalidEvent)
538 return false;
539 // An event handler can deref this object.
540 RefPtrWillBeRawPtr<HTMLFormControlElement> protector(this);
541 RefPtrWillBeRawPtr<Document> originalDocument(document());
542 bool needsDefaultAction = dispatchEvent(Event::createCancelable(EventTypeNames::invalid));
543 if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
544 unhandledInvalidControls->append(this);
545 return false;
548 void HTMLFormControlElement::showValidationMessage()
550 scrollIntoViewIfNeeded(false);
551 RefPtrWillBeRawPtr<HTMLFormControlElement> protector(this);
552 focus();
553 updateVisibleValidationMessage();
556 bool HTMLFormControlElement::reportValidity()
558 WillBeHeapVector<RefPtrWillBeMember<HTMLFormControlElement>> unhandledInvalidControls;
559 bool isValid = checkValidity(&unhandledInvalidControls, CheckValidityDispatchInvalidEvent);
560 if (isValid || unhandledInvalidControls.isEmpty())
561 return isValid;
562 ASSERT(unhandledInvalidControls.size() == 1);
563 ASSERT(unhandledInvalidControls[0].get() == this);
564 // Update layout now before calling isFocusable(), which has
565 // !layoutObject()->needsLayout() assertion.
566 document().updateLayoutIgnorePendingStylesheets();
567 if (isFocusable()) {
568 showValidationMessage();
569 return false;
571 if (document().frame()) {
572 String message("An invalid form control with name='%name' is not focusable.");
573 message.replace("%name", name());
574 document().addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, ErrorMessageLevel, message));
576 return false;
579 bool HTMLFormControlElement::matchesValidityPseudoClasses() const
581 return willValidate();
584 bool HTMLFormControlElement::isValidElement()
586 if (m_validityIsDirty) {
587 m_isValid = !willValidate() || valid();
588 m_validityIsDirty = false;
589 } else {
590 // If the following assertion fails, setNeedsValidityCheck() is not
591 // called correctly when something which changes validity is updated.
592 ASSERT(m_isValid == (!willValidate() || valid()));
594 return m_isValid;
597 void HTMLFormControlElement::setNeedsValidityCheck()
599 if (!m_validityIsDirty) {
600 m_validityIsDirty = true;
601 formOwnerSetNeedsValidityCheck();
602 fieldSetAncestorsSetNeedsValidityCheck(parentNode());
603 pseudoStateChanged(CSSSelector::PseudoValid);
604 pseudoStateChanged(CSSSelector::PseudoInvalid);
607 // Updates only if this control already has a validation message.
608 if (isValidationMessageVisible()) {
609 // Calls updateVisibleValidationMessage() even if m_isValid is not
610 // changed because a validation message can be changed.
611 updateVisibleValidationMessage();
615 void HTMLFormControlElement::setCustomValidity(const String& error)
617 FormAssociatedElement::setCustomValidity(error);
618 setNeedsValidityCheck();
621 void HTMLFormControlElement::dispatchBlurEvent(Element* newFocusedElement, WebFocusType type, InputDeviceCapabilities* sourceCapabilities)
623 if (type != WebFocusTypePage)
624 m_wasFocusedByMouse = false;
625 HTMLElement::dispatchBlurEvent(newFocusedElement, type, sourceCapabilities);
626 hideVisibleValidationMessage();
629 bool HTMLFormControlElement::isSuccessfulSubmitButton() const
631 return canBeSuccessfulSubmitButton() && !isDisabledFormControl();
634 bool HTMLFormControlElement::isDefaultButtonForForm() const
636 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
639 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
641 if (!node)
642 return nullptr;
643 return Traversal<HTMLFormControlElement>::firstAncestorOrSelf(*node);
646 String HTMLFormControlElement::nameForAutofill() const
648 String fullName = name();
649 String trimmedName = fullName.stripWhiteSpace();
650 if (!trimmedName.isEmpty())
651 return trimmedName;
652 fullName = getIdAttribute();
653 trimmedName = fullName.stripWhiteSpace();
654 return trimmedName;
657 void HTMLFormControlElement::setFocus(bool flag)
659 LabelableElement::setFocus(flag);
661 if (!flag && wasChangedSinceLastFormControlChangeEvent())
662 dispatchFormControlChangeEvent();
665 void HTMLFormControlElement::copyNonAttributePropertiesFromElement(const Element& source)
667 HTMLElement::copyNonAttributePropertiesFromElement(source);
668 setNeedsValidityCheck();
671 } // namespace blink