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