Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / html / HTMLFormControlElement.cpp
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 "ControlStates.h"
29 #include "ElementAncestorIterator.h"
30 #include "Event.h"
31 #include "EventHandler.h"
32 #include "EventNames.h"
33 #include "Frame.h"
34 #include "HTMLFieldSetElement.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLInputElement.h"
37 #include "HTMLLegendElement.h"
38 #include "HTMLTextAreaElement.h"
39 #include "RenderBox.h"
40 #include "RenderTheme.h"
41 #include "ValidationMessage.h"
42 #include <wtf/NeverDestroyed.h>
43 #include <wtf/Ref.h>
44 #include <wtf/Vector.h>
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
51     : LabelableElement(tagName, document)
52     , FormAssociatedElement(form)
53     , m_disabled(false)
54     , m_isReadOnly(false)
55     , m_isRequired(false)
56     , m_valueMatchesRenderer(false)
57     , m_disabledByAncestorFieldset(false)
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     setHasCustomStyleResolveCallbacks();
66 }
67
68 HTMLFormControlElement::~HTMLFormControlElement()
69 {
70     // The calls willChangeForm() and didChangeForm() are virtual, we want the
71     // form to be reset while this object still exists.
72     setForm(nullptr);
73 }
74
75 String HTMLFormControlElement::formEnctype() const
76 {
77     const AtomicString& formEnctypeAttr = fastGetAttribute(formenctypeAttr);
78     if (formEnctypeAttr.isNull())
79         return emptyString();
80     return FormSubmission::Attributes::parseEncodingType(formEnctypeAttr);
81 }
82
83 void HTMLFormControlElement::setFormEnctype(const String& value)
84 {
85     setAttribute(formenctypeAttr, value);
86 }
87
88 String HTMLFormControlElement::formMethod() const
89 {
90     const AtomicString& formMethodAttr = fastGetAttribute(formmethodAttr);
91     if (formMethodAttr.isNull())
92         return emptyString();
93     return FormSubmission::Attributes::methodString(FormSubmission::Attributes::parseMethodType(formMethodAttr));
94 }
95
96 void HTMLFormControlElement::setFormMethod(const String& value)
97 {
98     setAttribute(formmethodAttr, value);
99 }
100
101 bool HTMLFormControlElement::formNoValidate() const
102 {
103     return fastHasAttribute(formnovalidateAttr);
104 }
105
106 bool HTMLFormControlElement::computeIsDisabledByFieldsetAncestor() const
107 {
108     Element* previousAncestor = nullptr;
109     for (Element* ancestor = parentElement(); ancestor; ancestor = ancestor->parentElement()) {
110         if (is<HTMLFieldSetElement>(*ancestor) && ancestor->fastHasAttribute(disabledAttr)) {
111             HTMLFieldSetElement& fieldSetAncestor = downcast<HTMLFieldSetElement>(*ancestor);
112             bool isInFirstLegend = is<HTMLLegendElement>(previousAncestor) && previousAncestor == fieldSetAncestor.legend();
113             return !isInFirstLegend;
114         }
115         previousAncestor = ancestor;
116     }
117     return false;
118 }
119
120 void HTMLFormControlElement::setAncestorDisabled(bool isDisabled)
121 {
122     ASSERT(computeIsDisabledByFieldsetAncestor() == isDisabled);
123     bool oldValue = m_disabledByAncestorFieldset;
124     m_disabledByAncestorFieldset = isDisabled;
125     if (oldValue != m_disabledByAncestorFieldset)
126         disabledStateChanged();
127 }
128
129 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
130 {
131     if (name == formAttr)
132         formAttributeChanged();
133     else if (name == disabledAttr) {
134         bool oldDisabled = m_disabled;
135         m_disabled = !value.isNull();
136         if (oldDisabled != m_disabled)
137             disabledAttributeChanged();
138     } else if (name == readonlyAttr) {
139         bool wasReadOnly = m_isReadOnly;
140         m_isReadOnly = !value.isNull();
141         if (wasReadOnly != m_isReadOnly)
142             readOnlyAttributeChanged();
143     } else if (name == requiredAttr) {
144         bool wasRequired = m_isRequired;
145         m_isRequired = !value.isNull();
146         if (wasRequired != m_isRequired)
147             requiredAttributeChanged();
148     } else
149         HTMLElement::parseAttribute(name, value);
150 }
151
152 void HTMLFormControlElement::disabledAttributeChanged()
153 {
154     disabledStateChanged();
155 }
156
157 void HTMLFormControlElement::disabledStateChanged()
158 {
159     setNeedsWillValidateCheck();
160     setNeedsStyleRecalc();
161     if (renderer() && renderer()->style().hasAppearance())
162         renderer()->theme().stateChanged(*renderer(), ControlStates::EnabledState);
163 }
164
165 void HTMLFormControlElement::readOnlyAttributeChanged()
166 {
167     setNeedsWillValidateCheck();
168     setNeedsStyleRecalc();
169 }
170
171 void HTMLFormControlElement::requiredAttributeChanged()
172 {
173     updateValidity();
174     // Style recalculation is needed because style selectors may include
175     // :required and :optional pseudo-classes.
176     setNeedsStyleRecalc();
177 }
178
179 static bool shouldAutofocus(HTMLFormControlElement* element)
180 {
181     if (!element->renderer())
182         return false;
183     if (!element->fastHasAttribute(autofocusAttr))
184         return false;
185     if (!element->inDocument() || !element->document().renderView())
186         return false;
187     if (element->document().isSandboxed(SandboxAutomaticFeatures)) {
188         // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
189         element->document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, ASCIILiteral("Blocked autofocusing on a form control because the form's frame is sandboxed and the 'allow-scripts' permission is not set."));
190         return false;
191     }
192     if (element->hasAutofocused())
193         return false;
194
195     // FIXME: Should this set of hasTagName checks be replaced by a
196     // virtual member function?
197     if (is<HTMLInputElement>(*element))
198         return !downcast<HTMLInputElement>(*element).isInputTypeHidden();
199     if (element->hasTagName(selectTag))
200         return true;
201     if (element->hasTagName(keygenTag))
202         return true;
203     if (element->hasTagName(buttonTag))
204         return true;
205     if (is<HTMLTextAreaElement>(*element))
206         return true;
207
208     return false;
209 }
210
211 void HTMLFormControlElement::didAttachRenderers()
212 {
213     // The call to updateFromElement() needs to go after the call through
214     // to the base class's attach() because that can sometimes do a close
215     // on the renderer.
216     if (renderer())
217         renderer()->updateFromElement();
218
219     if (shouldAutofocus(this)) {
220         setAutofocused();
221
222         RefPtr<HTMLFormControlElement> element = this;
223         Style::queuePostResolutionCallback([element] {
224             element->focus();
225         });
226     }
227 }
228
229 void HTMLFormControlElement::didMoveToNewDocument(Document* oldDocument)
230 {
231     FormAssociatedElement::didMoveToNewDocument(oldDocument);
232     HTMLElement::didMoveToNewDocument(oldDocument);
233 }
234
235 static void addInvalidElementToAncestorFromInsertionPoint(const HTMLFormControlElement& element, ContainerNode* insertionPoint)
236 {
237     if (!is<Element>(insertionPoint))
238         return;
239
240     for (auto& ancestor : lineageOfType<HTMLFieldSetElement>(downcast<Element>(*insertionPoint)))
241         ancestor.addInvalidDescendant(element);
242 }
243
244 static void removeInvalidElementToAncestorFromInsertionPoint(const HTMLFormControlElement& element, ContainerNode* insertionPoint)
245 {
246     if (!is<Element>(insertionPoint))
247         return;
248
249     for (auto& ancestor : lineageOfType<HTMLFieldSetElement>(downcast<Element>(*insertionPoint)))
250         ancestor.removeInvalidDescendant(element);
251 }
252
253 Node::InsertionNotificationRequest HTMLFormControlElement::insertedInto(ContainerNode& insertionPoint)
254 {
255     if (willValidate() && !isValidFormControlElement())
256         addInvalidElementToAncestorFromInsertionPoint(*this, &insertionPoint);
257
258     if (document().hasDisabledFieldsetElement())
259         setAncestorDisabled(computeIsDisabledByFieldsetAncestor());
260     m_dataListAncestorState = Unknown;
261     setNeedsWillValidateCheck();
262     HTMLElement::insertedInto(insertionPoint);
263     FormAssociatedElement::insertedInto(insertionPoint);
264     return InsertionShouldCallFinishedInsertingSubtree;
265 }
266
267 void HTMLFormControlElement::finishedInsertingSubtree()
268 {
269     resetFormOwner();
270 }
271
272 void HTMLFormControlElement::removedFrom(ContainerNode& insertionPoint)
273 {
274     bool wasMatchingInvalidPseudoClass = willValidate() && !isValidFormControlElement();
275
276     m_validationMessage = nullptr;
277     if (m_disabledByAncestorFieldset)
278         setAncestorDisabled(computeIsDisabledByFieldsetAncestor());
279     m_dataListAncestorState = Unknown;
280     HTMLElement::removedFrom(insertionPoint);
281     FormAssociatedElement::removedFrom(insertionPoint);
282
283     if (wasMatchingInvalidPseudoClass)
284         removeInvalidElementToAncestorFromInsertionPoint(*this, &insertionPoint);
285 }
286
287 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
288 {
289     m_wasChangedSinceLastFormControlChangeEvent = changed;
290 }
291
292 void HTMLFormControlElement::dispatchChangeEvent()
293 {
294     dispatchScopedEvent(Event::create(eventNames().changeEvent, true, false));
295 }
296
297 void HTMLFormControlElement::dispatchFormControlChangeEvent()
298 {
299     dispatchChangeEvent();
300     setChangedSinceLastFormControlChangeEvent(false);
301 }
302
303 void HTMLFormControlElement::dispatchFormControlInputEvent()
304 {
305     setChangedSinceLastFormControlChangeEvent(true);
306     HTMLElement::dispatchInputEvent();
307 }
308
309 bool HTMLFormControlElement::isDisabledFormControl() const
310 {
311     return m_disabled || m_disabledByAncestorFieldset;
312 }
313
314 bool HTMLFormControlElement::isRequired() const
315 {
316     return m_isRequired;
317 }
318
319 void HTMLFormControlElement::didRecalcStyle(Style::Change)
320 {
321     // updateFromElement() can cause the selection to change, and in turn
322     // trigger synchronous layout, so it must not be called during style recalc.
323     if (renderer()) {
324         RefPtr<HTMLFormControlElement> element = this;
325         Style::queuePostResolutionCallback([element]{
326             if (auto* renderer = element->renderer())
327                 renderer->updateFromElement();
328         });
329     }
330 }
331
332 bool HTMLFormControlElement::supportsFocus() const
333 {
334     return !isDisabledFormControl();
335 }
336
337 bool HTMLFormControlElement::isFocusable() const
338 {
339     // If there's a renderer, make sure the size isn't empty, but if there's no renderer,
340     // it might still be focusable if it's in a canvas subtree (handled in Node::isFocusable).
341     if (renderer() && (!is<RenderBox>(*renderer()) || downcast<RenderBox>(*renderer()).size().isEmpty()))
342         return false;
343     // HTMLElement::isFocusable handles visibility and calls suportsFocus which
344     // will cover the disabled case.
345     return HTMLElement::isFocusable();
346 }
347
348 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
349 {
350     if (isFocusable())
351         if (document().frame())
352             return document().frame()->eventHandler().tabsToAllFormControls(event);
353     return false;
354 }
355
356 bool HTMLFormControlElement::isMouseFocusable() const
357 {
358 #if PLATFORM(GTK)
359     return HTMLElement::isMouseFocusable();
360 #else
361     return false;
362 #endif
363 }
364
365 bool HTMLFormControlElement::matchesValidPseudoClass() const
366 {
367     return willValidate() && isValidFormControlElement();
368 }
369
370 bool HTMLFormControlElement::matchesInvalidPseudoClass() const
371 {
372     return willValidate() && !isValidFormControlElement();
373 }
374
375 short HTMLFormControlElement::tabIndex() const
376 {
377     // Skip the supportsFocus check in HTMLElement.
378     return Element::tabIndex();
379 }
380
381 bool HTMLFormControlElement::computeWillValidate() const
382 {
383     if (m_dataListAncestorState == Unknown) {
384         for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) {
385             if (ancestor->hasTagName(datalistTag)) {
386                 m_dataListAncestorState = InsideDataList;
387                 break;
388             }
389         }
390         if (m_dataListAncestorState == Unknown)
391             m_dataListAncestorState = NotInsideDataList;
392     }
393     return m_dataListAncestorState == NotInsideDataList && !isDisabledOrReadOnly();
394 }
395
396 bool HTMLFormControlElement::willValidate() const
397 {
398     if (!m_willValidateInitialized || m_dataListAncestorState == Unknown) {
399         m_willValidateInitialized = true;
400         bool newWillValidate = computeWillValidate();
401         if (m_willValidate != newWillValidate)
402             m_willValidate = newWillValidate;
403     } else {
404         // If the following assertion fails, setNeedsWillValidateCheck() is not
405         // called correctly when something which changes computeWillValidate() result
406         // is updated.
407         ASSERT(m_willValidate == computeWillValidate());
408     }
409     return m_willValidate;
410 }
411
412 void HTMLFormControlElement::setNeedsWillValidateCheck()
413 {
414     // We need to recalculate willValidate immediately because willValidate change can causes style change.
415     bool newWillValidate = computeWillValidate();
416     if (m_willValidateInitialized && m_willValidate == newWillValidate)
417         return;
418
419     bool wasValid = m_isValid;
420
421     m_willValidateInitialized = true;
422     m_willValidate = newWillValidate;
423
424     updateValidity();
425     setNeedsStyleRecalc();
426
427     if (!m_willValidate && !wasValid) {
428         removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
429         if (HTMLFormElement* form = this->form())
430             form->removeInvalidAssociatedFormControlIfNeeded(*this);
431     }
432
433     if (!m_willValidate)
434         hideVisibleValidationMessage();
435 }
436
437 void HTMLFormControlElement::updateVisibleValidationMessage()
438 {
439     Page* page = document().page();
440     if (!page)
441         return;
442     String message;
443     if (renderer() && willValidate())
444         message = validationMessage().stripWhiteSpace();
445     if (!m_validationMessage)
446         m_validationMessage = std::make_unique<ValidationMessage>(this);
447     m_validationMessage->updateValidationMessage(message);
448 }
449
450 void HTMLFormControlElement::hideVisibleValidationMessage()
451 {
452     if (m_validationMessage)
453         m_validationMessage->requestToHideMessage();
454 }
455
456 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement>>* unhandledInvalidControls)
457 {
458     if (!willValidate() || isValidFormControlElement())
459         return true;
460     // An event handler can deref this object.
461     Ref<HTMLFormControlElement> protect(*this);
462     Ref<Document> originalDocument(document());
463     bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
464     if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument.ptr() == &document())
465         unhandledInvalidControls->append(this);
466     return false;
467 }
468
469 inline bool HTMLFormControlElement::isValidFormControlElement() const
470 {
471     // If the following assertion fails, updateValidity() is not called
472     // correctly when something which changes validity is updated.
473     ASSERT(m_isValid == valid());
474     return m_isValid;
475 }
476
477 void HTMLFormControlElement::willChangeForm()
478 {
479     if (HTMLFormElement* form = this->form())
480         form->removeInvalidAssociatedFormControlIfNeeded(*this);
481     FormAssociatedElement::willChangeForm();
482 }
483
484 void HTMLFormControlElement::didChangeForm()
485 {
486     FormAssociatedElement::didChangeForm();
487     if (HTMLFormElement* form = this->form()) {
488         if (m_willValidateInitialized && m_willValidate && !isValidFormControlElement())
489             form->registerInvalidAssociatedFormControl(*this);
490     }
491 }
492
493 void HTMLFormControlElement::updateValidity()
494 {
495     bool willValidate = this->willValidate();
496     bool wasValid = m_isValid;
497
498     m_isValid = valid();
499
500     if (willValidate && m_isValid != wasValid) {
501         // Update style for pseudo classes such as :valid :invalid.
502         setNeedsStyleRecalc();
503
504         if (!m_isValid) {
505             addInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
506             if (HTMLFormElement* form = this->form())
507                 form->registerInvalidAssociatedFormControl(*this);
508         } else {
509             removeInvalidElementToAncestorFromInsertionPoint(*this, parentNode());
510             if (HTMLFormElement* form = this->form())
511                 form->removeInvalidAssociatedFormControlIfNeeded(*this);
512         }
513     }
514
515     // Updates only if this control already has a validtion message.
516     if (m_validationMessage && m_validationMessage->isVisible()) {
517         // Calls updateVisibleValidationMessage() even if m_isValid is not
518         // changed because a validation message can be chagned.
519         updateVisibleValidationMessage();
520     }
521 }
522
523 void HTMLFormControlElement::setCustomValidity(const String& error)
524 {
525     FormAssociatedElement::setCustomValidity(error);
526     updateValidity();
527 }
528
529 bool HTMLFormControlElement::validationMessageShadowTreeContains(const Node& node) const
530 {
531     return m_validationMessage && m_validationMessage->shadowTreeContains(node);
532 }
533
534 void HTMLFormControlElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)
535 {
536     HTMLElement::dispatchBlurEvent(WTFMove(newFocusedElement));
537     hideVisibleValidationMessage();
538 }
539
540 HTMLFormElement* HTMLFormControlElement::virtualForm() const
541 {
542     return FormAssociatedElement::form();
543 }
544
545 bool HTMLFormControlElement::isDefaultButtonForForm() const
546 {
547     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
548 }
549
550 #if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
551 // FIXME: We should look to share these methods with class HTMLFormElement instead of duplicating them.
552
553 bool HTMLFormControlElement::autocorrect() const
554 {
555     const AtomicString& autocorrectValue = fastGetAttribute(autocorrectAttr);
556     if (!autocorrectValue.isEmpty())
557         return !equalIgnoringCase(autocorrectValue, "off");
558     if (HTMLFormElement* form = this->form())
559         return form->autocorrect();
560     return true;
561 }
562
563 void HTMLFormControlElement::setAutocorrect(bool autocorrect)
564 {
565     setAttribute(autocorrectAttr, autocorrect ? AtomicString("on", AtomicString::ConstructFromLiteral) : AtomicString("off", AtomicString::ConstructFromLiteral));
566 }
567
568 WebAutocapitalizeType HTMLFormControlElement::autocapitalizeType() const
569 {
570     WebAutocapitalizeType type = autocapitalizeTypeForAttributeValue(fastGetAttribute(autocapitalizeAttr));
571     if (type == WebAutocapitalizeTypeDefault) {
572         if (HTMLFormElement* form = this->form())
573             return form->autocapitalizeType();
574     }
575     return type;
576 }
577
578 const AtomicString& HTMLFormControlElement::autocapitalize() const
579 {
580     return stringForAutocapitalizeType(autocapitalizeType());
581 }
582
583 void HTMLFormControlElement::setAutocapitalize(const AtomicString& value)
584 {
585     setAttribute(autocapitalizeAttr, value);
586 }
587 #endif
588
589 HTMLFormControlElement* HTMLFormControlElement::enclosingFormControlElement(Node* node)
590 {
591     for (; node; node = node->parentNode()) {
592         if (is<HTMLFormControlElement>(*node))
593             return downcast<HTMLFormControlElement>(node);
594     }
595     return nullptr;
596 }
597
598 static inline bool isContactToken(const AtomicString& token)
599 {
600     return token == "home" || token == "work" || token == "mobile" || token == "fax" || token == "pager";
601 }
602
603 enum class AutofillCategory {
604     Invalid,
605     Off,
606     Automatic,
607     Normal,
608     Contact,
609 };
610
611 static inline AutofillCategory categoryForAutofillFieldToken(const AtomicString& token)
612 {
613     static NeverDestroyed<HashMap<AtomicString, AutofillCategory>> map;
614     if (map.get().isEmpty()) {
615         map.get().add(AtomicString("off", AtomicString::ConstructFromLiteral), AutofillCategory::Off);
616         map.get().add(AtomicString("on", AtomicString::ConstructFromLiteral), AutofillCategory::Automatic);
617
618         map.get().add(AtomicString("name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
619         map.get().add(AtomicString("honorific-prefix", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
620         map.get().add(AtomicString("given-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
621         map.get().add(AtomicString("additional-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
622         map.get().add(AtomicString("family-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
623         map.get().add(AtomicString("honorific-suffix", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
624         map.get().add(AtomicString("nickname", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
625         map.get().add(AtomicString("username", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
626         map.get().add(AtomicString("new-password", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
627         map.get().add(AtomicString("current-password", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
628         map.get().add(AtomicString("organization-title", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
629         map.get().add(AtomicString("organization", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
630         map.get().add(AtomicString("street-address", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
631         map.get().add(AtomicString("address-line1", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
632         map.get().add(AtomicString("address-line2", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
633         map.get().add(AtomicString("address-line3", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
634         map.get().add(AtomicString("address-level4", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
635         map.get().add(AtomicString("address-level3", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
636         map.get().add(AtomicString("address-level2", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
637         map.get().add(AtomicString("address-level1", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
638         map.get().add(AtomicString("country", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
639         map.get().add(AtomicString("country-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
640         map.get().add(AtomicString("postal-code", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
641         map.get().add(AtomicString("cc-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
642         map.get().add(AtomicString("cc-given-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
643         map.get().add(AtomicString("cc-additional-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
644         map.get().add(AtomicString("cc-family-name", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
645         map.get().add(AtomicString("cc-number", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
646         map.get().add(AtomicString("cc-exp", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
647         map.get().add(AtomicString("cc-exp-month", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
648         map.get().add(AtomicString("cc-exp-year", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
649         map.get().add(AtomicString("cc-csc", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
650         map.get().add(AtomicString("cc-type", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
651         map.get().add(AtomicString("transaction-currency", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
652         map.get().add(AtomicString("transaction-amount", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
653         map.get().add(AtomicString("language", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
654         map.get().add(AtomicString("bday", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
655         map.get().add(AtomicString("bday-day", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
656         map.get().add(AtomicString("bday-month", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
657         map.get().add(AtomicString("bday-year", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
658         map.get().add(AtomicString("sex", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
659         map.get().add(AtomicString("url", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
660         map.get().add(AtomicString("photo", AtomicString::ConstructFromLiteral), AutofillCategory::Normal);
661
662         map.get().add(AtomicString("tel", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
663         map.get().add(AtomicString("tel-country-code", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
664         map.get().add(AtomicString("tel-national", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
665         map.get().add(AtomicString("tel-area-code", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
666         map.get().add(AtomicString("tel-local", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
667         map.get().add(AtomicString("tel-local-prefix", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
668         map.get().add(AtomicString("tel-local-suffix", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
669         map.get().add(AtomicString("tel-extension", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
670         map.get().add(AtomicString("email", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
671         map.get().add(AtomicString("impp", AtomicString::ConstructFromLiteral), AutofillCategory::Contact);
672     }
673
674     return map.get().get(token);
675 }
676
677 static inline unsigned maxTokensForAutofillFieldCategory(AutofillCategory category)
678 {
679     switch (category) {
680     case AutofillCategory::Invalid:
681         return 0;
682
683     case AutofillCategory::Automatic:
684     case AutofillCategory::Off:
685         return 1;
686
687     case AutofillCategory::Normal:
688         return 3;
689
690     case AutofillCategory::Contact:
691         return 4;
692     }
693     ASSERT_NOT_REACHED();
694     return 0;
695 }
696
697 // https://html.spec.whatwg.org/multipage/forms.html#processing-model-3
698 String HTMLFormControlElement::autocomplete() const
699 {
700     const AtomicString& attributeValue = fastGetAttribute(autocompleteAttr);
701     SpaceSplitString tokens(attributeValue, true);
702     if (tokens.isEmpty())
703         return String();
704
705     size_t currentTokenIndex = tokens.size() - 1;
706     const auto& fieldToken = tokens[currentTokenIndex];
707     auto category = categoryForAutofillFieldToken(fieldToken);
708     if (category == AutofillCategory::Invalid)
709         return String();
710
711     if (tokens.size() > maxTokensForAutofillFieldCategory(category))
712         return String();
713
714     bool wearingAutofillAnchorMantle = is<HTMLInputElement>(*this) && downcast<HTMLInputElement>(this)->isInputTypeHidden();
715     if ((category == AutofillCategory::Off || category == AutofillCategory::Automatic) && wearingAutofillAnchorMantle)
716         return String();
717
718     if (category == AutofillCategory::Off)
719         return ASCIILiteral("off");
720
721     if (category == AutofillCategory::Automatic)
722         return ASCIILiteral("on");
723
724     String result = fieldToken;
725     if (!currentTokenIndex--)
726         return result;
727
728     const auto& contactToken = tokens[currentTokenIndex];
729     if (category == AutofillCategory::Contact && isContactToken(contactToken)) {
730         result = contactToken + " " + result;
731         if (!currentTokenIndex--)
732             return result;
733     }
734
735     const auto& modeToken = tokens[currentTokenIndex];
736     if (modeToken == "shipping" || modeToken == "billing") {
737         result = modeToken + " " + result;
738         if (!currentTokenIndex--)
739             return result;
740     }
741
742     if (currentTokenIndex)
743         return String();
744
745     const auto& sectionToken = tokens[currentTokenIndex];
746     if (!sectionToken.startsWith("section-"))
747         return String();
748
749     return sectionToken + " " + result;
750 }
751
752 void HTMLFormControlElement::setAutocomplete(const String& value)
753 {
754     setAttribute(autocompleteAttr, value);
755 }
756
757 } // namespace Webcore