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