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