[Datalist] Display prefix-matched suggestions first
[WebKit-https.git] / Source / WebCore / html / TextFieldInputType.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "TextFieldInputType.h"
34
35 #include "BeforeTextInsertedEvent.h"
36 #include "Chrome.h"
37 #include "ChromeClient.h"
38 #include "DOMFormData.h"
39 #include "Editor.h"
40 #include "EventNames.h"
41 #include "Frame.h"
42 #include "FrameSelection.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLNames.h"
45 #include "HTMLParserIdioms.h"
46 #include "KeyboardEvent.h"
47 #include "LocalizedStrings.h"
48 #include "NodeRenderStyle.h"
49 #include "Page.h"
50 #include "PlatformKeyboardEvent.h"
51 #include "RenderLayer.h"
52 #include "RenderTextControlSingleLine.h"
53 #include "RenderTheme.h"
54 #include "ShadowRoot.h"
55 #include "TextControlInnerElements.h"
56 #include "TextEvent.h"
57 #include "TextIterator.h"
58 #include "TextNodeTraversal.h"
59 #include "WheelEvent.h"
60
61 #if ENABLE(DATALIST_ELEMENT)
62 #include "HTMLDataListElement.h"
63 #include "HTMLOptionElement.h"
64 #endif
65
66 namespace WebCore {
67
68 using namespace HTMLNames;
69
70 TextFieldInputType::TextFieldInputType(HTMLInputElement& element)
71     : InputType(element)
72 {
73 }
74
75 TextFieldInputType::~TextFieldInputType()
76 {
77     if (m_innerSpinButton)
78         m_innerSpinButton->removeSpinButtonOwner();
79 #if ENABLE(DATALIST_ELEMENT)
80     closeSuggestions();
81 #endif
82 }
83
84 bool TextFieldInputType::isKeyboardFocusable(KeyboardEvent*) const
85 {
86     ASSERT(element());
87 #if PLATFORM(IOS)
88     if (element()->isReadOnly())
89         return false;
90 #endif
91     return element()->isTextFormControlFocusable();
92 }
93
94 bool TextFieldInputType::isMouseFocusable() const
95 {
96     ASSERT(element());
97     return element()->isTextFormControlFocusable();
98 }
99
100 bool TextFieldInputType::isTextField() const
101 {
102     return true;
103 }
104
105 bool TextFieldInputType::isEmptyValue() const
106 {
107     auto innerText = innerTextElement();
108     ASSERT(innerText);
109
110     for (Text* text = TextNodeTraversal::firstWithin(*innerText); text; text = TextNodeTraversal::next(*text, innerText.get())) {
111         if (text->length())
112             return false;
113     }
114     return true;
115 }
116
117 bool TextFieldInputType::valueMissing(const String& value) const
118 {
119     ASSERT(element());
120     return element()->isRequired() && value.isEmpty();
121 }
122
123 void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
124 {
125     ASSERT(element());
126
127     // Grab this input element to keep reference even if JS event handler
128     // changes input type.
129     Ref<HTMLInputElement> input(*element());
130
131     // We don't ask InputType::setValue to dispatch events because
132     // TextFieldInputType dispatches events different way from InputType.
133     InputType::setValue(sanitizedValue, valueChanged, DispatchNoEvent);
134
135     if (valueChanged)
136         updateInnerTextValue();
137
138     unsigned max = visibleValue().length();
139     if (input->focused())
140         input->setSelectionRange(max, max);
141     else
142         input->cacheSelectionInResponseToSetValue(max);
143
144     if (!valueChanged)
145         return;
146
147     switch (eventBehavior) {
148     case DispatchChangeEvent:
149         // If the user is still editing this field, dispatch an input event rather than a change event.
150         // The change event will be dispatched when editing finishes.
151         if (input->focused())
152             input->dispatchFormControlInputEvent();
153         else
154             input->dispatchFormControlChangeEvent();
155         break;
156
157     case DispatchInputAndChangeEvent: {
158         input->dispatchFormControlInputEvent();
159         input->dispatchFormControlChangeEvent();
160         break;
161     }
162
163     case DispatchNoEvent:
164         break;
165     }
166
167     // FIXME: Why do we do this when eventBehavior == DispatchNoEvent
168     if (!input->focused() || eventBehavior == DispatchNoEvent)
169         input->setTextAsOfLastFormControlChangeEvent(sanitizedValue);
170 }
171
172 #if ENABLE(DATALIST_ELEMENT)
173 void TextFieldInputType::handleClickEvent(MouseEvent&)
174 {
175     if (element()->focused() && element()->list())
176         displaySuggestions(DataListSuggestionActivationType::ControlClicked);
177 }
178 #endif
179
180 void TextFieldInputType::handleKeydownEvent(KeyboardEvent& event)
181 {
182     ASSERT(element());
183     if (!element()->focused())
184         return;
185 #if ENABLE(DATALIST_ELEMENT)
186     const String& key = event.keyIdentifier();
187     if (m_suggestionPicker && (key == "Enter" || key == "Up" || key == "Down")) {
188         m_suggestionPicker->handleKeydownWithIdentifier(key);
189         event.setDefaultHandled();
190     }
191 #endif
192     RefPtr<Frame> frame = element()->document().frame();
193     if (!frame || !frame->editor().doTextFieldCommandFromEvent(element(), &event))
194         return;
195     event.setDefaultHandled();
196 }
197
198 void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent& event)
199 {
200     ASSERT(element());
201     if (element()->isDisabledOrReadOnly())
202         return;
203 #if ENABLE(DATALIST_ELEMENT)
204     if (m_suggestionPicker)
205         return;
206 #endif
207     const String& key = event.keyIdentifier();
208     if (key == "Up")
209         spinButtonStepUp();
210     else if (key == "Down")
211         spinButtonStepDown();
212     else
213         return;
214     event.setDefaultHandled();
215 }
216
217 void TextFieldInputType::forwardEvent(Event& event)
218 {
219     if (m_innerSpinButton) {
220         m_innerSpinButton->forwardEvent(event);
221         if (event.defaultHandled())
222             return;
223     }
224
225     bool isFocusEvent = event.type() == eventNames().focusEvent;
226     bool isBlurEvent = event.type() == eventNames().blurEvent;
227     if (isFocusEvent || isBlurEvent)
228         capsLockStateMayHaveChanged();
229     if (event.isMouseEvent() || isFocusEvent || isBlurEvent) {
230         ASSERT(element());
231         element()->forwardEvent(event);
232     }
233 }
234
235 void TextFieldInputType::elementDidBlur()
236 {
237     ASSERT(element());
238     auto* renderer = element()->renderer();
239     if (!renderer)
240         return;
241
242     auto* innerTextRenderer = innerTextElement()->renderer();
243     if (!innerTextRenderer)
244         return;
245
246     auto* innerLayer = innerTextRenderer->layer();
247     if (!innerLayer)
248         return;
249
250     bool isLeftToRightDirection = downcast<RenderTextControlSingleLine>(*renderer).style().isLeftToRightDirection();
251     ScrollOffset scrollOffset(isLeftToRightDirection ? 0 : innerLayer->scrollWidth(), 0);
252     innerLayer->scrollToOffset(scrollOffset);
253
254 #if ENABLE(DATALIST_ELEMENT)
255     closeSuggestions();
256 #endif
257 }
258
259 void TextFieldInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection)
260 {
261     ASSERT(element());
262     ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != element());
263     if (RefPtr<Frame> frame = element()->document().frame())
264         frame->editor().textFieldDidBeginEditing(element());
265 }
266
267 void TextFieldInputType::handleBlurEvent()
268 {
269     InputType::handleBlurEvent();
270     ASSERT(element());
271     element()->endEditing();
272 }
273
274 bool TextFieldInputType::shouldSubmitImplicitly(Event& event)
275 {
276     return (event.type() == eventNames().textInputEvent && is<TextEvent>(event) && downcast<TextEvent>(event).data() == "\n")
277         || InputType::shouldSubmitImplicitly(event);
278 }
279
280 RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(RenderStyle&& style)
281 {
282     ASSERT(element());
283     return createRenderer<RenderTextControlSingleLine>(*element(), WTFMove(style));
284 }
285
286 bool TextFieldInputType::needsContainer() const
287 {
288 #if ENABLE(DATALIST_ELEMENT)
289     return element()->hasAttributeWithoutSynchronization(listAttr);
290 #endif
291     return false;
292 }
293
294 bool TextFieldInputType::shouldHaveSpinButton() const
295 {
296     ASSERT(element());
297     return RenderTheme::singleton().shouldHaveSpinButton(*element());
298 }
299
300 bool TextFieldInputType::shouldHaveCapsLockIndicator() const
301 {
302     ASSERT(element());
303     return RenderTheme::singleton().shouldHaveCapsLockIndicator(*element());
304 }
305
306 void TextFieldInputType::createShadowSubtree()
307 {
308     ASSERT(element());
309     ASSERT(element()->shadowRoot());
310
311     ASSERT(!m_innerText);
312     ASSERT(!m_innerBlock);
313     ASSERT(!m_innerSpinButton);
314     ASSERT(!m_capsLockIndicator);
315     ASSERT(!m_autoFillButton);
316
317     Document& document = element()->document();
318     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
319     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
320     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
321
322     m_innerText = TextControlInnerTextElement::create(document);
323
324     if (!createsContainer) {
325         element()->userAgentShadowRoot()->appendChild(*m_innerText);
326         updatePlaceholderText();
327         return;
328     }
329
330     createContainer();
331     updatePlaceholderText();
332
333     if (shouldHaveSpinButton) {
334         m_innerSpinButton = SpinButtonElement::create(document, *this);
335         m_container->appendChild(*m_innerSpinButton);
336     }
337
338     if (shouldHaveCapsLockIndicator) {
339         m_capsLockIndicator = HTMLDivElement::create(document);
340         m_capsLockIndicator->setPseudo(AtomicString("-webkit-caps-lock-indicator", AtomicString::ConstructFromLiteral));
341
342         bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
343         m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
344
345         m_container->appendChild(*m_capsLockIndicator);
346     }
347
348     updateAutoFillButton();
349
350 #if ENABLE(DATALIST_ELEMENT)
351     m_dataListDropdownIndicator = DataListButtonElement::create(element()->document(), *this);
352     m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);
353     m_container->appendChild(*m_dataListDropdownIndicator);
354 #endif
355 }
356
357 HTMLElement* TextFieldInputType::containerElement() const
358 {
359     return m_container.get();
360 }
361
362 HTMLElement* TextFieldInputType::innerBlockElement() const
363 {
364     return m_innerBlock.get();
365 }
366
367 RefPtr<TextControlInnerTextElement> TextFieldInputType::innerTextElement() const
368 {
369     ASSERT(m_innerText);
370     return m_innerText;
371 }
372
373 HTMLElement* TextFieldInputType::innerSpinButtonElement() const
374 {
375     return m_innerSpinButton.get();
376 }
377
378 HTMLElement* TextFieldInputType::capsLockIndicatorElement() const
379 {
380     return m_capsLockIndicator.get();
381 }
382
383 HTMLElement* TextFieldInputType::autoFillButtonElement() const
384 {
385     return m_autoFillButton.get();
386 }
387
388 HTMLElement* TextFieldInputType::placeholderElement() const
389 {
390     return m_placeholder.get();
391 }
392
393 void TextFieldInputType::destroyShadowSubtree()
394 {
395     InputType::destroyShadowSubtree();
396     m_innerText = nullptr;
397     m_placeholder = nullptr;
398     m_innerBlock = nullptr;
399     if (m_innerSpinButton)
400         m_innerSpinButton->removeSpinButtonOwner();
401     m_innerSpinButton = nullptr;
402     m_capsLockIndicator = nullptr;
403     m_autoFillButton = nullptr;
404 #if ENABLE(DATALIST)
405     m_dataListDropdownIndicator = nullptr;
406 #endif
407     m_container = nullptr;
408 }
409
410 void TextFieldInputType::attributeChanged(const QualifiedName& name)
411 {
412     if (name == valueAttr || name == placeholderAttr) {
413         if (element())
414             updateInnerTextValue();
415     }
416     InputType::attributeChanged(name);
417 }
418
419 void TextFieldInputType::disabledStateChanged()
420 {
421     if (m_innerSpinButton)
422         m_innerSpinButton->releaseCapture();
423     capsLockStateMayHaveChanged();
424     updateAutoFillButton();
425 }
426
427 void TextFieldInputType::readOnlyStateChanged()
428 {
429     if (m_innerSpinButton)
430         m_innerSpinButton->releaseCapture();
431     capsLockStateMayHaveChanged();
432     updateAutoFillButton();
433 }
434
435 bool TextFieldInputType::supportsReadOnly() const
436 {
437     return true;
438 }
439
440 bool TextFieldInputType::shouldUseInputMethod() const
441 {
442     return true;
443 }
444
445 // FIXME: The name of this function doesn't make clear the two jobs it does:
446 // 1) Limits the string to a particular number of grapheme clusters.
447 // 2) Truncates the string at the first character which is a control character other than tab.
448 // FIXME: TextFieldInputType::sanitizeValue doesn't need a limit on grapheme clusters. A limit on code units would do.
449 // FIXME: Where does the "truncate at first control character" rule come from?
450 static String limitLength(const String& string, unsigned maxNumGraphemeClusters)
451 {
452     StringView stringView { string };
453     unsigned firstNonTabControlCharacterIndex = stringView.find([] (UChar character) {
454         return character < ' ' && character != '\t';
455     });
456     unsigned limitedLength;
457     if (stringView.is8Bit())
458         limitedLength = std::min(firstNonTabControlCharacterIndex, maxNumGraphemeClusters);
459     else
460         limitedLength = numCodeUnitsInGraphemeClusters(stringView.substring(0, firstNonTabControlCharacterIndex), maxNumGraphemeClusters);
461     return string.left(limitedLength);
462 }
463
464 static String autoFillButtonTypeToAccessibilityLabel(AutoFillButtonType autoFillButtonType)
465 {
466     switch (autoFillButtonType) {
467     case AutoFillButtonType::Contacts:
468         return AXAutoFillContactsLabel();
469     case AutoFillButtonType::Credentials:
470         return AXAutoFillCredentialsLabel();
471     case AutoFillButtonType::StrongPassword:
472         return AXAutoFillStrongPasswordLabel();
473     case AutoFillButtonType::None:
474         ASSERT_NOT_REACHED();
475         return { };
476     }
477     ASSERT_NOT_REACHED();
478     return { };
479 }
480
481 static String autoFillButtonTypeToAutoFillButtonText(AutoFillButtonType autoFillButtonType)
482 {
483     switch (autoFillButtonType) {
484     case AutoFillButtonType::Contacts:
485     case AutoFillButtonType::Credentials:
486         return emptyString();
487     case AutoFillButtonType::StrongPassword:
488         return autoFillStrongPasswordLabel();
489     case AutoFillButtonType::None:
490         ASSERT_NOT_REACHED();
491         return { };
492     }
493     ASSERT_NOT_REACHED();
494     return { };
495 }
496
497 static AtomicString autoFillButtonTypeToAutoFillButtonPseudoClassName(AutoFillButtonType autoFillButtonType)
498 {
499     switch (autoFillButtonType) {
500     case AutoFillButtonType::Contacts:
501         return { "-webkit-contacts-auto-fill-button", AtomicString::ConstructFromLiteral };
502     case AutoFillButtonType::Credentials:
503         return { "-webkit-credentials-auto-fill-button", AtomicString::ConstructFromLiteral };
504     case AutoFillButtonType::StrongPassword:
505         return { "-webkit-strong-password-auto-fill-button", AtomicString::ConstructFromLiteral };
506     case AutoFillButtonType::None:
507         ASSERT_NOT_REACHED();
508         return emptyAtom();
509     }
510     ASSERT_NOT_REACHED();
511     return { };
512 }
513
514 static bool isAutoFillButtonTypeChanged(const AtomicString& attribute, AutoFillButtonType autoFillButtonType)
515 {
516     if (attribute == "-webkit-contacts-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Contacts)
517         return true;
518     if (attribute == "-webkit-credentials-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Credentials)
519         return true;
520     if (attribute == "-webkit-strong-password-auto-fill-button" && autoFillButtonType != AutoFillButtonType::StrongPassword)
521         return true;
522     return false;
523 }
524
525 String TextFieldInputType::sanitizeValue(const String& proposedValue) const
526 {
527     return limitLength(proposedValue.removeCharacters(isHTMLLineBreak), HTMLInputElement::maxEffectiveLength);
528 }
529
530 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent& event)
531 {
532     ASSERT(element());
533     // Make sure that the text to be inserted will not violate the maxLength.
534
535     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
536     // because they can be mismatched by sanitizeValue() in
537     // HTMLInputElement::subtreeHasChanged() in some cases.
538     String innerText = element()->innerTextValue();
539     unsigned oldLength = numGraphemeClusters(innerText);
540
541     // selectionLength represents the selection length of this text field to be
542     // removed by this insertion.
543     // If the text field has no focus, we don't need to take account of the
544     // selection length. The selection is the source of text drag-and-drop in
545     // that case, and nothing in the text field will be removed.
546     unsigned selectionLength = 0;
547     if (element()->focused()) {
548         ASSERT(enclosingTextFormControl(element()->document().frame()->selection().selection().start()) == element());
549         int selectionStart = element()->selectionStart();
550         ASSERT(selectionStart <= element()->selectionEnd());
551         int selectionCodeUnitCount = element()->selectionEnd() - selectionStart;
552         selectionLength = selectionCodeUnitCount ? numGraphemeClusters(StringView(innerText).substring(selectionStart, selectionCodeUnitCount)) : 0;
553     }
554     ASSERT(oldLength >= selectionLength);
555
556     // Selected characters will be removed by the next text event.
557     unsigned baseLength = oldLength - selectionLength;
558     unsigned maxLength = isTextType() ? element()->effectiveMaxLength() : HTMLInputElement::maxEffectiveLength;
559     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
560
561     // Truncate the inserted text to avoid violating the maxLength and other constraints.
562     String eventText = event.text();
563     unsigned textLength = eventText.length();
564     while (textLength > 0 && isHTMLLineBreak(eventText[textLength - 1]))
565         textLength--;
566     eventText.truncate(textLength);
567     eventText.replace("\r\n", " ");
568     eventText.replace('\r', ' ');
569     eventText.replace('\n', ' ');
570     event.setText(limitLength(eventText, appendableLength));
571 }
572
573 bool TextFieldInputType::shouldRespectListAttribute()
574 {
575 #if ENABLE(DATALIST_ELEMENT)
576     return true;
577 #else
578     return InputType::themeSupportsDataListUI(this);
579 #endif
580 }
581
582 void TextFieldInputType::updatePlaceholderText()
583 {
584     if (!supportsPlaceholder())
585         return;
586     ASSERT(element());
587     String placeholderText = element()->strippedPlaceholder();
588     if (placeholderText.isEmpty()) {
589         if (m_placeholder) {
590             m_placeholder->parentNode()->removeChild(*m_placeholder);
591             m_placeholder = nullptr;
592         }
593         return;
594     }
595     if (!m_placeholder) {
596         m_placeholder = TextControlPlaceholderElement::create(element()->document());
597         element()->userAgentShadowRoot()->insertBefore(*m_placeholder, m_container ? m_container.get() : innerTextElement().get());
598     }
599     m_placeholder->setInnerText(placeholderText);
600 }
601
602 bool TextFieldInputType::appendFormData(DOMFormData& formData, bool multipart) const
603 {
604     InputType::appendFormData(formData, multipart);
605     ASSERT(element());
606     auto& dirnameAttrValue = element()->attributeWithoutSynchronization(dirnameAttr);
607     if (!dirnameAttrValue.isNull())
608         formData.append(dirnameAttrValue, element()->directionForFormData());
609     return true;
610 }
611
612 String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
613 {
614     return visibleValue;
615 }
616
617 void TextFieldInputType::subtreeHasChanged()
618 {
619     ASSERT(element());
620     element()->setChangedSinceLastFormControlChangeEvent(true);
621
622     // We don't need to call sanitizeUserInputValue() function here because
623     // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
624     // sanitizeUserInputValue().
625     // ---
626     // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
627     // ---
628     // Input types that support the selection API do *not* sanitize their
629     // user input in order to retain parity between what's in the model and
630     // what's on the screen. Otherwise, we retain the sanitization process for
631     // backward compatibility. https://bugs.webkit.org/show_bug.cgi?id=150346
632     String innerText = convertFromVisibleValue(element()->innerTextValue());
633     if (!supportsSelectionAPI())
634         innerText = sanitizeValue(innerText);
635     element()->setValueFromRenderer(innerText);
636     element()->updatePlaceholderVisibility();
637     // Recalc for :invalid change.
638     element()->invalidateStyleForSubtree();
639
640     didSetValueByUserEdit();
641 }
642
643 void TextFieldInputType::didSetValueByUserEdit()
644 {
645     ASSERT(element());
646     if (!element()->focused())
647         return;
648     if (RefPtr<Frame> frame = element()->document().frame())
649         frame->editor().textDidChangeInTextField(element());
650 #if ENABLE(DATALIST_ELEMENT)
651     if (element()->list())
652         displaySuggestions(DataListSuggestionActivationType::TextChanged);
653 #endif
654 }
655
656 void TextFieldInputType::spinButtonStepDown()
657 {
658     stepUpFromRenderer(-1);
659 }
660
661 void TextFieldInputType::spinButtonStepUp()
662 {
663     stepUpFromRenderer(1);
664 }
665
666 void TextFieldInputType::updateInnerTextValue()
667 {
668     ASSERT(element());
669     if (!element()->formControlValueMatchesRenderer()) {
670         // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
671         // It protects an unacceptable renderer value from being overwritten with the DOM value.
672         element()->setInnerTextValue(visibleValue());
673         element()->updatePlaceholderVisibility();
674     }
675 }
676
677 void TextFieldInputType::focusAndSelectSpinButtonOwner()
678 {
679     ASSERT(element());
680     Ref<HTMLInputElement> input(*element());
681     input->focus();
682     input->select();
683 }
684
685 bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
686 {
687     ASSERT(element());
688     return !element()->isDisabledOrReadOnly();
689 }
690
691 bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
692 {
693     ASSERT(element());
694     return shouldSpinButtonRespondToMouseEvents() && element()->focused();
695 }
696
697 bool TextFieldInputType::shouldDrawCapsLockIndicator() const
698 {
699     ASSERT(element());
700     if (element()->document().focusedElement() != element())
701         return false;
702
703     if (element()->isDisabledOrReadOnly())
704         return false;
705
706     RefPtr<Frame> frame = element()->document().frame();
707     if (!frame)
708         return false;
709
710     if (!frame->selection().isFocusedAndActive())
711         return false;
712
713     return PlatformKeyboardEvent::currentCapsLockState();
714 }
715
716 void TextFieldInputType::capsLockStateMayHaveChanged()
717 {
718     if (!m_capsLockIndicator)
719         return;
720
721     bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
722     m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
723 }
724
725 bool TextFieldInputType::shouldDrawAutoFillButton() const
726 {
727     ASSERT(element());
728     return !element()->isDisabledOrReadOnly() && element()->autoFillButtonType() != AutoFillButtonType::None;
729 }
730
731 void TextFieldInputType::autoFillButtonElementWasClicked()
732 {
733     ASSERT(element());
734     Page* page = element()->document().page();
735     if (!page)
736         return;
737
738     page->chrome().client().handleAutoFillButtonClick(*element());
739 }
740
741 void TextFieldInputType::createContainer()
742 {
743     ASSERT(!m_container);
744     ASSERT(element());
745
746     m_container = TextControlInnerContainer::create(element()->document());
747     m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
748
749     m_innerBlock = TextControlInnerElement::create(element()->document());
750     m_innerBlock->appendChild(*m_innerText);
751     m_container->appendChild(*m_innerBlock);
752
753     element()->userAgentShadowRoot()->appendChild(*m_container);
754 }
755
756 void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonType)
757 {
758     ASSERT(!m_autoFillButton);
759
760     if (autoFillButtonType == AutoFillButtonType::None)
761         return;
762
763     ASSERT(element());
764     m_autoFillButton = AutoFillButtonElement::create(element()->document(), *this);
765     m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
766     m_autoFillButton->setAttributeWithoutSynchronization(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
767     m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
768     m_autoFillButton->setTextContent(autoFillButtonTypeToAutoFillButtonText(autoFillButtonType));
769     m_container->appendChild(*m_autoFillButton);
770 }
771
772 void TextFieldInputType::updateAutoFillButton()
773 {
774     if (shouldDrawAutoFillButton()) {
775         if (!m_container)
776             createContainer();
777
778         ASSERT(element());
779         AutoFillButtonType autoFillButtonType = element()->autoFillButtonType();
780         if (!m_autoFillButton)
781             createAutoFillButton(autoFillButtonType);
782
783         const AtomicString& attribute = m_autoFillButton->attributeWithoutSynchronization(pseudoAttr);
784         bool shouldUpdateAutoFillButtonType = isAutoFillButtonTypeChanged(attribute, autoFillButtonType);
785         if (shouldUpdateAutoFillButtonType) {
786             m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
787             m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
788             m_autoFillButton->setTextContent(autoFillButtonTypeToAutoFillButtonText(autoFillButtonType));
789         }
790         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock, true);
791         return;
792     }
793     
794     if (m_autoFillButton)
795         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);        
796 }
797
798 #if ENABLE(DATALIST_ELEMENT)
799
800 void TextFieldInputType::listAttributeTargetChanged()
801 {
802     m_cachedSuggestions = std::make_pair(String(), Vector<String>());
803
804     if (!m_dataListDropdownIndicator)
805         return;
806
807     m_dataListDropdownIndicator->setInlineStyleProperty(CSSPropertyDisplay, element()->list() ? CSSValueBlock : CSSValueNone, true);
808 }
809
810 HTMLElement* TextFieldInputType::dataListButtonElement() const
811 {
812     return m_dataListDropdownIndicator.get();
813 }
814
815 void TextFieldInputType::dataListButtonElementWasClicked()
816 {
817     if (element()->list())
818         displaySuggestions(DataListSuggestionActivationType::IndicatorClicked);
819 }
820
821 IntRect TextFieldInputType::elementRectInRootViewCoordinates() const
822 {
823     if (!element()->renderer())
824         return IntRect();
825     return element()->document().view()->contentsToRootView(element()->renderer()->absoluteBoundingBoxRect());
826 }
827
828 Vector<String> TextFieldInputType::suggestions()
829 {
830     Vector<String> suggestions;
831     Vector<String> matchesContainingValue;
832
833     String elementValue = element()->value();
834
835     if (!m_cachedSuggestions.first.isNull() && equalIgnoringASCIICase(m_cachedSuggestions.first, elementValue))
836         return m_cachedSuggestions.second;
837
838     if (auto dataList = element()->dataList()) {
839         Ref<HTMLCollection> options = dataList->options();
840         for (unsigned i = 0; auto* option = downcast<HTMLOptionElement>(options->item(i)); ++i) {
841             if (!element()->isValidValue(option->value()))
842                 continue;
843
844             String value = sanitizeValue(option->value());
845             if (elementValue.isEmpty())
846                 suggestions.append(value);
847             else if (value.startsWithIgnoringASCIICase(elementValue))
848                 suggestions.append(value);
849             else if (value.containsIgnoringASCIICase(elementValue))
850                 matchesContainingValue.append(value);
851         }
852     }
853
854     suggestions.appendVector(matchesContainingValue);
855     m_cachedSuggestions = std::make_pair(elementValue, suggestions);
856
857     return suggestions;
858 }
859
860 void TextFieldInputType::didSelectDataListOption(const String& selectedOption)
861 {
862     element()->setValue(selectedOption, DispatchInputAndChangeEvent);
863 }
864
865 void TextFieldInputType::didCloseSuggestions()
866 {
867     m_cachedSuggestions = std::make_pair(String(), Vector<String>());
868     m_suggestionPicker = nullptr;
869     if (element()->renderer())
870         element()->renderer()->repaint();
871 }
872
873 void TextFieldInputType::displaySuggestions(DataListSuggestionActivationType type)
874 {
875     if (element()->isDisabledFormControl() || !element()->renderer())
876         return;
877
878     if (!UserGestureIndicator::processingUserGesture())
879         return;
880
881     if (!m_suggestionPicker && suggestions().size() > 0)
882         m_suggestionPicker = chrome()->createDataListSuggestionPicker(*this);
883
884     if (!m_suggestionPicker)
885         return;
886
887     m_suggestionPicker->displayWithActivationType(type);
888 }
889
890 void TextFieldInputType::closeSuggestions()
891 {
892     if (m_suggestionPicker)
893         m_suggestionPicker->close();
894 }
895
896 bool TextFieldInputType::isPresentingAttachedView() const
897 {
898     return !!m_suggestionPicker;
899 }
900
901 #endif
902
903 } // namespace WebCore