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