[Datalist] Allow TextFieldInputType to show and hide suggestions
[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 #endif
190     RefPtr<Frame> frame = element()->document().frame();
191     if (!frame || !frame->editor().doTextFieldCommandFromEvent(element(), &event))
192         return;
193     event.setDefaultHandled();
194 }
195
196 void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent& event)
197 {
198     ASSERT(element());
199     if (element()->isDisabledOrReadOnly())
200         return;
201     const String& key = event.keyIdentifier();
202     if (key == "Up")
203         spinButtonStepUp();
204     else if (key == "Down")
205         spinButtonStepDown();
206     else
207         return;
208     event.setDefaultHandled();
209 }
210
211 void TextFieldInputType::forwardEvent(Event& event)
212 {
213     if (m_innerSpinButton) {
214         m_innerSpinButton->forwardEvent(event);
215         if (event.defaultHandled())
216             return;
217     }
218
219     bool isFocusEvent = event.type() == eventNames().focusEvent;
220     bool isBlurEvent = event.type() == eventNames().blurEvent;
221     if (isFocusEvent || isBlurEvent)
222         capsLockStateMayHaveChanged();
223     if (event.isMouseEvent() || isFocusEvent || isBlurEvent) {
224         ASSERT(element());
225         element()->forwardEvent(event);
226     }
227 }
228
229 void TextFieldInputType::elementDidBlur()
230 {
231     ASSERT(element());
232     auto* renderer = element()->renderer();
233     if (!renderer)
234         return;
235
236     auto* innerTextRenderer = innerTextElement()->renderer();
237     if (!innerTextRenderer)
238         return;
239
240     auto* innerLayer = innerTextRenderer->layer();
241     if (!innerLayer)
242         return;
243
244     bool isLeftToRightDirection = downcast<RenderTextControlSingleLine>(*renderer).style().isLeftToRightDirection();
245     ScrollOffset scrollOffset(isLeftToRightDirection ? 0 : innerLayer->scrollWidth(), 0);
246     innerLayer->scrollToOffset(scrollOffset);
247
248 #if ENABLE(DATALIST_ELEMENT)
249     closeSuggestions();
250 #endif
251 }
252
253 void TextFieldInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection)
254 {
255     ASSERT(element());
256     ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != element());
257     if (RefPtr<Frame> frame = element()->document().frame())
258         frame->editor().textFieldDidBeginEditing(element());
259 }
260
261 void TextFieldInputType::handleBlurEvent()
262 {
263     InputType::handleBlurEvent();
264     ASSERT(element());
265     element()->endEditing();
266 }
267
268 bool TextFieldInputType::shouldSubmitImplicitly(Event& event)
269 {
270     return (event.type() == eventNames().textInputEvent && is<TextEvent>(event) && downcast<TextEvent>(event).data() == "\n")
271         || InputType::shouldSubmitImplicitly(event);
272 }
273
274 RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(RenderStyle&& style)
275 {
276     ASSERT(element());
277     return createRenderer<RenderTextControlSingleLine>(*element(), WTFMove(style));
278 }
279
280 bool TextFieldInputType::needsContainer() const
281 {
282     return false;
283 }
284
285 bool TextFieldInputType::shouldHaveSpinButton() const
286 {
287     ASSERT(element());
288     return RenderTheme::singleton().shouldHaveSpinButton(*element());
289 }
290
291 bool TextFieldInputType::shouldHaveCapsLockIndicator() const
292 {
293     ASSERT(element());
294     return RenderTheme::singleton().shouldHaveCapsLockIndicator(*element());
295 }
296
297 void TextFieldInputType::createShadowSubtree()
298 {
299     ASSERT(element());
300     ASSERT(element()->shadowRoot());
301
302     ASSERT(!m_innerText);
303     ASSERT(!m_innerBlock);
304     ASSERT(!m_innerSpinButton);
305     ASSERT(!m_capsLockIndicator);
306     ASSERT(!m_autoFillButton);
307
308     Document& document = element()->document();
309     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
310     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
311     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
312
313     m_innerText = TextControlInnerTextElement::create(document);
314
315     if (!createsContainer) {
316         element()->userAgentShadowRoot()->appendChild(*m_innerText);
317         updatePlaceholderText();
318         return;
319     }
320
321     createContainer();
322     updatePlaceholderText();
323
324     if (shouldHaveSpinButton) {
325         m_innerSpinButton = SpinButtonElement::create(document, *this);
326         m_container->appendChild(*m_innerSpinButton);
327     }
328
329     if (shouldHaveCapsLockIndicator) {
330         m_capsLockIndicator = HTMLDivElement::create(document);
331         m_capsLockIndicator->setPseudo(AtomicString("-webkit-caps-lock-indicator", AtomicString::ConstructFromLiteral));
332
333         bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
334         m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
335
336         m_container->appendChild(*m_capsLockIndicator);
337     }
338
339     updateAutoFillButton();
340 }
341
342 HTMLElement* TextFieldInputType::containerElement() const
343 {
344     return m_container.get();
345 }
346
347 HTMLElement* TextFieldInputType::innerBlockElement() const
348 {
349     return m_innerBlock.get();
350 }
351
352 RefPtr<TextControlInnerTextElement> TextFieldInputType::innerTextElement() const
353 {
354     ASSERT(m_innerText);
355     return m_innerText;
356 }
357
358 HTMLElement* TextFieldInputType::innerSpinButtonElement() const
359 {
360     return m_innerSpinButton.get();
361 }
362
363 HTMLElement* TextFieldInputType::capsLockIndicatorElement() const
364 {
365     return m_capsLockIndicator.get();
366 }
367
368 HTMLElement* TextFieldInputType::autoFillButtonElement() const
369 {
370     return m_autoFillButton.get();
371 }
372
373 HTMLElement* TextFieldInputType::placeholderElement() const
374 {
375     return m_placeholder.get();
376 }
377
378 void TextFieldInputType::destroyShadowSubtree()
379 {
380     InputType::destroyShadowSubtree();
381     m_innerText = nullptr;
382     m_placeholder = nullptr;
383     m_innerBlock = nullptr;
384     if (m_innerSpinButton)
385         m_innerSpinButton->removeSpinButtonOwner();
386     m_innerSpinButton = nullptr;
387     m_capsLockIndicator = nullptr;
388     m_autoFillButton = nullptr;
389     m_container = nullptr;
390 }
391
392 void TextFieldInputType::attributeChanged(const QualifiedName& name)
393 {
394     if (name == valueAttr || name == placeholderAttr) {
395         if (element())
396             updateInnerTextValue();
397     }
398     InputType::attributeChanged(name);
399 }
400
401 void TextFieldInputType::disabledStateChanged()
402 {
403     if (m_innerSpinButton)
404         m_innerSpinButton->releaseCapture();
405     capsLockStateMayHaveChanged();
406     updateAutoFillButton();
407 }
408
409 void TextFieldInputType::readOnlyStateChanged()
410 {
411     if (m_innerSpinButton)
412         m_innerSpinButton->releaseCapture();
413     capsLockStateMayHaveChanged();
414     updateAutoFillButton();
415 }
416
417 bool TextFieldInputType::supportsReadOnly() const
418 {
419     return true;
420 }
421
422 bool TextFieldInputType::shouldUseInputMethod() const
423 {
424     return true;
425 }
426
427 // FIXME: The name of this function doesn't make clear the two jobs it does:
428 // 1) Limits the string to a particular number of grapheme clusters.
429 // 2) Truncates the string at the first character which is a control character other than tab.
430 // FIXME: TextFieldInputType::sanitizeValue doesn't need a limit on grapheme clusters. A limit on code units would do.
431 // FIXME: Where does the "truncate at first control character" rule come from?
432 static String limitLength(const String& string, unsigned maxNumGraphemeClusters)
433 {
434     StringView stringView { string };
435     unsigned firstNonTabControlCharacterIndex = stringView.find([] (UChar character) {
436         return character < ' ' && character != '\t';
437     });
438     unsigned limitedLength;
439     if (stringView.is8Bit())
440         limitedLength = std::min(firstNonTabControlCharacterIndex, maxNumGraphemeClusters);
441     else
442         limitedLength = numCodeUnitsInGraphemeClusters(stringView.substring(0, firstNonTabControlCharacterIndex), maxNumGraphemeClusters);
443     return string.left(limitedLength);
444 }
445
446 static String autoFillButtonTypeToAccessibilityLabel(AutoFillButtonType autoFillButtonType)
447 {
448     switch (autoFillButtonType) {
449     case AutoFillButtonType::Contacts:
450         return AXAutoFillContactsLabel();
451     case AutoFillButtonType::Credentials:
452         return AXAutoFillCredentialsLabel();
453     case AutoFillButtonType::StrongConfirmationPassword:
454         return AXAutoFillStrongConfirmationPasswordLabel();
455     case AutoFillButtonType::StrongPassword:
456         return AXAutoFillStrongPasswordLabel();
457     case AutoFillButtonType::None:
458         ASSERT_NOT_REACHED();
459         return { };
460     }
461     ASSERT_NOT_REACHED();
462     return { };
463 }
464
465 static String autoFillButtonTypeToAutoFillButtonText(AutoFillButtonType autoFillButtonType)
466 {
467     switch (autoFillButtonType) {
468     case AutoFillButtonType::Contacts:
469     case AutoFillButtonType::Credentials:
470     case AutoFillButtonType::StrongConfirmationPassword:
471         return emptyString();
472     case AutoFillButtonType::StrongPassword:
473         return autoFillStrongPasswordLabel();
474     case AutoFillButtonType::None:
475         ASSERT_NOT_REACHED();
476         return { };
477     }
478     ASSERT_NOT_REACHED();
479     return { };
480 }
481
482 static AtomicString autoFillButtonTypeToAutoFillButtonPseudoClassName(AutoFillButtonType autoFillButtonType)
483 {
484     switch (autoFillButtonType) {
485     case AutoFillButtonType::Contacts:
486         return { "-webkit-contacts-auto-fill-button", AtomicString::ConstructFromLiteral };
487     case AutoFillButtonType::Credentials:
488         return { "-webkit-credentials-auto-fill-button", AtomicString::ConstructFromLiteral };
489     case AutoFillButtonType::StrongConfirmationPassword:
490         return { "-webkit-strong-confirmation-password-auto-fill-button", AtomicString::ConstructFromLiteral };
491     case AutoFillButtonType::StrongPassword:
492         return { "-webkit-strong-password-auto-fill-button", AtomicString::ConstructFromLiteral };
493     case AutoFillButtonType::None:
494         ASSERT_NOT_REACHED();
495         return emptyAtom();
496     }
497     ASSERT_NOT_REACHED();
498     return { };
499 }
500
501 static bool isAutoFillButtonTypeChanged(const AtomicString& attribute, AutoFillButtonType autoFillButtonType)
502 {
503     if (attribute == "-webkit-contacts-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Contacts)
504         return true;
505     if (attribute == "-webkit-credentials-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Credentials)
506         return true;
507     if (attribute == "-webkit-strong-confirmation-password-auto-fill-button" && autoFillButtonType != AutoFillButtonType::StrongConfirmationPassword)
508         return true;
509     if (attribute == "-webkit-strong-password-auto-fill-button" && autoFillButtonType != AutoFillButtonType::StrongPassword)
510         return true;
511     return false;
512 }
513
514 String TextFieldInputType::sanitizeValue(const String& proposedValue) const
515 {
516     return limitLength(proposedValue.removeCharacters(isHTMLLineBreak), HTMLInputElement::maxEffectiveLength);
517 }
518
519 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent& event)
520 {
521     ASSERT(element());
522     // Make sure that the text to be inserted will not violate the maxLength.
523
524     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
525     // because they can be mismatched by sanitizeValue() in
526     // HTMLInputElement::subtreeHasChanged() in some cases.
527     String innerText = element()->innerTextValue();
528     unsigned oldLength = numGraphemeClusters(innerText);
529
530     // selectionLength represents the selection length of this text field to be
531     // removed by this insertion.
532     // If the text field has no focus, we don't need to take account of the
533     // selection length. The selection is the source of text drag-and-drop in
534     // that case, and nothing in the text field will be removed.
535     unsigned selectionLength = 0;
536     if (element()->focused()) {
537         ASSERT(enclosingTextFormControl(element()->document().frame()->selection().selection().start()) == element());
538         int selectionStart = element()->selectionStart();
539         ASSERT(selectionStart <= element()->selectionEnd());
540         int selectionCodeUnitCount = element()->selectionEnd() - selectionStart;
541         selectionLength = selectionCodeUnitCount ? numGraphemeClusters(StringView(innerText).substring(selectionStart, selectionCodeUnitCount)) : 0;
542     }
543     ASSERT(oldLength >= selectionLength);
544
545     // Selected characters will be removed by the next text event.
546     unsigned baseLength = oldLength - selectionLength;
547     unsigned maxLength = isTextType() ? element()->effectiveMaxLength() : HTMLInputElement::maxEffectiveLength;
548     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
549
550     // Truncate the inserted text to avoid violating the maxLength and other constraints.
551     String eventText = event.text();
552     unsigned textLength = eventText.length();
553     while (textLength > 0 && isHTMLLineBreak(eventText[textLength - 1]))
554         textLength--;
555     eventText.truncate(textLength);
556     eventText.replace("\r\n", " ");
557     eventText.replace('\r', ' ');
558     eventText.replace('\n', ' ');
559     event.setText(limitLength(eventText, appendableLength));
560 }
561
562 bool TextFieldInputType::shouldRespectListAttribute()
563 {
564 #if ENABLE(DATALIST_ELEMENT)
565     return true;
566 #else
567     return InputType::themeSupportsDataListUI(this);
568 #endif
569 }
570
571 void TextFieldInputType::updatePlaceholderText()
572 {
573     if (!supportsPlaceholder())
574         return;
575     ASSERT(element());
576     String placeholderText = element()->strippedPlaceholder();
577     if (placeholderText.isEmpty()) {
578         if (m_placeholder) {
579             m_placeholder->parentNode()->removeChild(*m_placeholder);
580             m_placeholder = nullptr;
581         }
582         return;
583     }
584     if (!m_placeholder) {
585         m_placeholder = TextControlPlaceholderElement::create(element()->document());
586         element()->userAgentShadowRoot()->insertBefore(*m_placeholder, m_container ? m_container.get() : innerTextElement().get());
587     }
588     m_placeholder->setInnerText(placeholderText);
589 }
590
591 bool TextFieldInputType::appendFormData(DOMFormData& formData, bool multipart) const
592 {
593     InputType::appendFormData(formData, multipart);
594     ASSERT(element());
595     auto& dirnameAttrValue = element()->attributeWithoutSynchronization(dirnameAttr);
596     if (!dirnameAttrValue.isNull())
597         formData.append(dirnameAttrValue, element()->directionForFormData());
598     return true;
599 }
600
601 String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
602 {
603     return visibleValue;
604 }
605
606 void TextFieldInputType::subtreeHasChanged()
607 {
608     ASSERT(element());
609     element()->setChangedSinceLastFormControlChangeEvent(true);
610
611     // We don't need to call sanitizeUserInputValue() function here because
612     // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
613     // sanitizeUserInputValue().
614     // ---
615     // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
616     // ---
617     // Input types that support the selection API do *not* sanitize their
618     // user input in order to retain parity between what's in the model and
619     // what's on the screen. Otherwise, we retain the sanitization process for
620     // backward compatibility. https://bugs.webkit.org/show_bug.cgi?id=150346
621     String innerText = convertFromVisibleValue(element()->innerTextValue());
622     if (!supportsSelectionAPI())
623         innerText = sanitizeValue(innerText);
624     element()->setValueFromRenderer(innerText);
625     element()->updatePlaceholderVisibility();
626     // Recalc for :invalid change.
627     element()->invalidateStyleForSubtree();
628
629     didSetValueByUserEdit();
630 }
631
632 void TextFieldInputType::didSetValueByUserEdit()
633 {
634     ASSERT(element());
635     if (!element()->focused())
636         return;
637     if (RefPtr<Frame> frame = element()->document().frame())
638         frame->editor().textDidChangeInTextField(element());
639 #if ENABLE(DATALIST_ELEMENT)
640     if (element()->list())
641         displaySuggestions(DataListSuggestionActivationType::TextChanged);
642 #endif
643 }
644
645 void TextFieldInputType::spinButtonStepDown()
646 {
647     stepUpFromRenderer(-1);
648 }
649
650 void TextFieldInputType::spinButtonStepUp()
651 {
652     stepUpFromRenderer(1);
653 }
654
655 void TextFieldInputType::updateInnerTextValue()
656 {
657     ASSERT(element());
658     if (!element()->formControlValueMatchesRenderer()) {
659         // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
660         // It protects an unacceptable renderer value from being overwritten with the DOM value.
661         element()->setInnerTextValue(visibleValue());
662         element()->updatePlaceholderVisibility();
663     }
664 }
665
666 void TextFieldInputType::focusAndSelectSpinButtonOwner()
667 {
668     ASSERT(element());
669     Ref<HTMLInputElement> input(*element());
670     input->focus();
671     input->select();
672 }
673
674 bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
675 {
676     ASSERT(element());
677     return !element()->isDisabledOrReadOnly();
678 }
679
680 bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
681 {
682     ASSERT(element());
683     return shouldSpinButtonRespondToMouseEvents() && element()->focused();
684 }
685
686 bool TextFieldInputType::shouldDrawCapsLockIndicator() const
687 {
688     ASSERT(element());
689     if (element()->document().focusedElement() != element())
690         return false;
691
692     if (element()->isDisabledOrReadOnly())
693         return false;
694
695     RefPtr<Frame> frame = element()->document().frame();
696     if (!frame)
697         return false;
698
699     if (!frame->selection().isFocusedAndActive())
700         return false;
701
702     return PlatformKeyboardEvent::currentCapsLockState();
703 }
704
705 void TextFieldInputType::capsLockStateMayHaveChanged()
706 {
707     if (!m_capsLockIndicator)
708         return;
709
710     bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
711     m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
712 }
713
714 bool TextFieldInputType::shouldDrawAutoFillButton() const
715 {
716     ASSERT(element());
717     return !element()->isDisabledOrReadOnly() && element()->autoFillButtonType() != AutoFillButtonType::None;
718 }
719
720 void TextFieldInputType::autoFillButtonElementWasClicked()
721 {
722     ASSERT(element());
723     Page* page = element()->document().page();
724     if (!page)
725         return;
726
727     page->chrome().client().handleAutoFillButtonClick(*element());
728 }
729
730 void TextFieldInputType::createContainer()
731 {
732     ASSERT(!m_container);
733     ASSERT(element());
734
735     m_container = TextControlInnerContainer::create(element()->document());
736     m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
737
738     m_innerBlock = TextControlInnerElement::create(element()->document());
739     m_innerBlock->appendChild(*m_innerText);
740     m_container->appendChild(*m_innerBlock);
741
742     element()->userAgentShadowRoot()->appendChild(*m_container);
743 }
744
745 void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonType)
746 {
747     ASSERT(!m_autoFillButton);
748
749     if (autoFillButtonType == AutoFillButtonType::None)
750         return;
751
752     ASSERT(element());
753     m_autoFillButton = AutoFillButtonElement::create(element()->document(), *this);
754     m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
755     m_autoFillButton->setAttributeWithoutSynchronization(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
756     m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
757     m_autoFillButton->setTextContent(autoFillButtonTypeToAutoFillButtonText(autoFillButtonType));
758     m_container->appendChild(*m_autoFillButton);
759 }
760
761 void TextFieldInputType::updateAutoFillButton()
762 {
763     if (shouldDrawAutoFillButton()) {
764         if (!m_container)
765             createContainer();
766
767         ASSERT(element());
768         AutoFillButtonType autoFillButtonType = element()->autoFillButtonType();
769         if (!m_autoFillButton)
770             createAutoFillButton(autoFillButtonType);
771
772         const AtomicString& attribute = m_autoFillButton->attributeWithoutSynchronization(pseudoAttr);
773         bool shouldUpdateAutoFillButtonType = isAutoFillButtonTypeChanged(attribute, autoFillButtonType);
774         if (shouldUpdateAutoFillButtonType) {
775             m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
776             m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
777             m_autoFillButton->setTextContent(autoFillButtonTypeToAutoFillButtonText(autoFillButtonType));
778         }
779         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock, true);
780         return;
781     }
782     
783     if (m_autoFillButton)
784         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);        
785 }
786
787 #if ENABLE(DATALIST_ELEMENT)
788
789 IntRect TextFieldInputType::elementRectInRootViewCoordinates() const
790 {
791     if (!element()->renderer())
792         return IntRect();
793     return element()->document().view()->contentsToRootView(element()->renderer()->absoluteBoundingBoxRect());
794 }
795
796 Vector<String> TextFieldInputType::suggestions() const
797 {
798     Vector<String> suggestions;
799
800     if (auto dataList = element()->dataList()) {
801         Ref<HTMLCollection> options = dataList->options();
802         for (unsigned i = 0; auto* option = downcast<HTMLOptionElement>(options->item(i)); ++i) {
803             if (!element()->isValidValue(option->value()))
804                 continue;
805
806             String value = sanitizeValue(option->value());
807             if (!suggestions.contains(value) && (element()->value().isEmpty() || value.containsIgnoringASCIICase(element()->value())))
808                 suggestions.append(value);
809         }
810     }
811
812     return suggestions;
813 }
814
815 void TextFieldInputType::didSelectDataListOption(const String& selectedOption)
816 {
817     element()->setValue(selectedOption, DispatchInputAndChangeEvent);
818 }
819
820 void TextFieldInputType::didCloseSuggestions()
821 {
822     m_suggestionPicker = nullptr;
823 }
824
825 void TextFieldInputType::displaySuggestions(DataListSuggestionActivationType type)
826 {
827     if (element()->isDisabledFormControl() || !element()->renderer())
828         return;
829
830     if (!UserGestureIndicator::processingUserGesture())
831         return;
832
833     if (!m_suggestionPicker && suggestions().size() > 0)
834         m_suggestionPicker = chrome()->createDataListSuggestionPicker(*this);
835
836     if (!m_suggestionPicker)
837         return;
838
839     m_suggestionPicker->displayWithActivationType(type);
840 }
841
842 void TextFieldInputType::closeSuggestions()
843 {
844     if (m_suggestionPicker)
845         m_suggestionPicker->close();
846 }
847
848 #endif
849
850 } // namespace WebCore