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 "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
HTMLFormControlElement(const QualifiedName & tagName,Document & document,HTMLFormElement * form)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
~HTMLFormControlElement()68 HTMLFormControlElement::~HTMLFormControlElement()
69 {
70 setForm(0);
71 }
72
formEnctype() const73 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
setFormEnctype(const AtomicString & value)81 void HTMLFormControlElement::setFormEnctype(const AtomicString& value)
82 {
83 setAttribute(formenctypeAttr, value);
84 }
85
formMethod() const86 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
setFormMethod(const AtomicString & value)94 void HTMLFormControlElement::setFormMethod(const AtomicString& value)
95 {
96 setAttribute(formmethodAttr, value);
97 }
98
formNoValidate() const99 bool HTMLFormControlElement::formNoValidate() const
100 {
101 return fastHasAttribute(formnovalidateAttr);
102 }
103
updateAncestorDisabledState() const104 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
ancestorDisabledStateWasChanged()119 void HTMLFormControlElement::ancestorDisabledStateWasChanged()
120 {
121 m_ancestorDisabledState = AncestorDisabledStateUnknown;
122 disabledAttributeChanged();
123 }
124
reset()125 void HTMLFormControlElement::reset()
126 {
127 setAutofilled(false);
128 resetImpl();
129 }
130
parseAttribute(const QualifiedName & name,const AtomicString & value)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
disabledAttributeChanged()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
requiredAttributeChanged()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
focusPostAttach(Node * element)184 static void focusPostAttach(Node* element)
185 {
186 toElement(element)->focus();
187 element->deref();
188 }
189
isAutofocusable() const190 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
setAutofilled(bool autofilled)210 void HTMLFormControlElement::setAutofilled(bool autofilled)
211 {
212 if (autofilled == m_isAutofilled)
213 return;
214
215 m_isAutofilled = autofilled;
216 setNeedsStyleRecalc();
217 }
218
shouldAutofocusOnAttach(const HTMLFormControlElement * element)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
attach(const AttachContext & context)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
didMoveToNewDocument(Document & oldDocument)253 void HTMLFormControlElement::didMoveToNewDocument(Document& oldDocument)
254 {
255 FormAssociatedElement::didMoveToNewDocument(oldDocument);
256 HTMLElement::didMoveToNewDocument(oldDocument);
257 }
258
insertedInto(ContainerNode * insertionPoint)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
removedFrom(ContainerNode * insertionPoint)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
wasChangedSinceLastFormControlChangeEvent() const278 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
279 {
280 return m_wasChangedSinceLastFormControlChangeEvent;
281 }
282
setChangedSinceLastFormControlChangeEvent(bool changed)283 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
284 {
285 m_wasChangedSinceLastFormControlChangeEvent = changed;
286 }
287
dispatchFormControlChangeEvent()288 void HTMLFormControlElement::dispatchFormControlChangeEvent()
289 {
290 HTMLElement::dispatchChangeEvent();
291 setChangedSinceLastFormControlChangeEvent(false);
292 }
293
dispatchFormControlInputEvent()294 void HTMLFormControlElement::dispatchFormControlInputEvent()
295 {
296 setChangedSinceLastFormControlChangeEvent(true);
297 HTMLElement::dispatchInputEvent();
298 }
299
formOwner() const300 HTMLFormElement* HTMLFormControlElement::formOwner() const
301 {
302 return FormAssociatedElement::form();
303 }
304
isDisabledFormControl() const305 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
isRequired() const315 bool HTMLFormControlElement::isRequired() const
316 {
317 return m_isRequired;
318 }
319
resultForDialogSubmit()320 String HTMLFormControlElement::resultForDialogSubmit()
321 {
322 return fastGetAttribute(valueAttr);
323 }
324
updateFromElementCallback(Node * node)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
didRecalcStyle(StyleRecalcChange)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
supportsFocus() const341 bool HTMLFormControlElement::supportsFocus() const
342 {
343 return !isDisabledFormControl();
344 }
345
isKeyboardFocusable() const346 bool HTMLFormControlElement::isKeyboardFocusable() const
347 {
348 // Skip tabIndex check in a parent class.
349 return isFocusable();
350 }
351
shouldShowFocusRingOnMouseFocus() const352 bool HTMLFormControlElement::shouldShowFocusRingOnMouseFocus() const
353 {
354 return false;
355 }
356
dispatchFocusEvent(Element * oldFocusedElement,FocusDirection direction)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
shouldHaveFocusAppearance() const364 bool HTMLFormControlElement::shouldHaveFocusAppearance() const
365 {
366 ASSERT(focused());
367 return shouldShowFocusRingOnMouseFocus() || !m_wasFocusedByMouse;
368 }
369
willCallDefaultEventHandler(const Event & event)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
tabIndex() const382 short HTMLFormControlElement::tabIndex() const
383 {
384 // Skip the supportsFocus check in HTMLElement.
385 return Element::tabIndex();
386 }
387
recalcWillValidate() const388 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
willValidate() const403 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
setNeedsWillValidateCheck()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
updateVisibleValidationMessage()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
hideVisibleValidationMessage()448 void HTMLFormControlElement::hideVisibleValidationMessage()
449 {
450 if (m_validationMessage)
451 m_validationMessage->requestToHideMessage();
452 }
453
checkValidity(Vector<RefPtr<FormAssociatedElement>> * unhandledInvalidControls,CheckValidityDispatchEvents dispatchEvents)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
isValidFormControlElement()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
setNeedsValidityCheck()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
setCustomValidity(const String & error)494 void HTMLFormControlElement::setCustomValidity(const String& error)
495 {
496 FormAssociatedElement::setCustomValidity(error);
497 setNeedsValidityCheck();
498 }
499
dispatchBlurEvent(Element * newFocusedElement)500 void HTMLFormControlElement::dispatchBlurEvent(Element* newFocusedElement)
501 {
502 HTMLElement::dispatchBlurEvent(newFocusedElement);
503 hideVisibleValidationMessage();
504 }
505
isSuccessfulSubmitButton() const506 bool HTMLFormControlElement::isSuccessfulSubmitButton() const
507 {
508 return canBeSuccessfulSubmitButton() && !isDisabledFormControl();
509 }
510
isDefaultButtonForForm() const511 bool HTMLFormControlElement::isDefaultButtonForForm() const
512 {
513 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
514 }
515
enclosingFormControlElement(Node * node)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
nameForAutofill() const525 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