Make it possible to test rubber-banding in overflow scroll
[WebKit-https.git] / Source / WebCore / html / TextFieldInputType.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2011, 2014 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 namespace WebCore {
62
63 using namespace HTMLNames;
64
65 TextFieldInputType::TextFieldInputType(HTMLInputElement& element)
66     : InputType(element)
67 {
68 }
69
70 TextFieldInputType::~TextFieldInputType()
71 {
72     if (m_innerSpinButton)
73         m_innerSpinButton->removeSpinButtonOwner();
74 }
75
76 bool TextFieldInputType::isKeyboardFocusable(KeyboardEvent&) const
77 {
78 #if PLATFORM(IOS)
79     if (element().isReadOnly())
80         return false;
81 #endif
82     return element().isTextFormControlFocusable();
83 }
84
85 bool TextFieldInputType::isMouseFocusable() const
86 {
87     return element().isTextFormControlFocusable();
88 }
89
90 bool TextFieldInputType::isTextField() const
91 {
92     return true;
93 }
94
95 bool TextFieldInputType::isEmptyValue() const
96 {
97     auto innerText = innerTextElement();
98     ASSERT(innerText);
99
100     for (Text* text = TextNodeTraversal::firstWithin(*innerText); text; text = TextNodeTraversal::next(*text, innerText.get())) {
101         if (text->length())
102             return false;
103     }
104     return true;
105 }
106
107 bool TextFieldInputType::valueMissing(const String& value) const
108 {
109     return element().isRequired() && value.isEmpty();
110 }
111
112 void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
113 {
114     // Grab this input element to keep reference even if JS event handler
115     // changes input type.
116     Ref<HTMLInputElement> input(element());
117
118     // We don't ask InputType::setValue to dispatch events because
119     // TextFieldInputType dispatches events different way from InputType.
120     InputType::setValue(sanitizedValue, valueChanged, DispatchNoEvent);
121
122     if (valueChanged)
123         updateInnerTextValue();
124
125     unsigned max = visibleValue().length();
126     if (input->focused())
127         input->setSelectionRange(max, max);
128     else
129         input->cacheSelectionInResponseToSetValue(max);
130
131     if (!valueChanged)
132         return;
133
134     switch (eventBehavior) {
135     case DispatchChangeEvent:
136         // If the user is still editing this field, dispatch an input event rather than a change event.
137         // The change event will be dispatched when editing finishes.
138         if (input->focused())
139             input->dispatchFormControlInputEvent();
140         else
141             input->dispatchFormControlChangeEvent();
142         break;
143
144     case DispatchInputAndChangeEvent: {
145         input->dispatchFormControlInputEvent();
146         input->dispatchFormControlChangeEvent();
147         break;
148     }
149
150     case DispatchNoEvent:
151         break;
152     }
153
154     // FIXME: Why do we do this when eventBehavior == DispatchNoEvent
155     if (!input->focused() || eventBehavior == DispatchNoEvent)
156         input->setTextAsOfLastFormControlChangeEvent(sanitizedValue);
157 }
158
159 void TextFieldInputType::handleKeydownEvent(KeyboardEvent& event)
160 {
161     if (!element().focused())
162         return;
163     RefPtr<Frame> frame = element().document().frame();
164     if (!frame || !frame->editor().doTextFieldCommandFromEvent(&element(), &event))
165         return;
166     event.setDefaultHandled();
167 }
168
169 void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent& event)
170 {
171     if (element().isDisabledOrReadOnly())
172         return;
173     const String& key = event.keyIdentifier();
174     if (key == "Up")
175         spinButtonStepUp();
176     else if (key == "Down")
177         spinButtonStepDown();
178     else
179         return;
180     event.setDefaultHandled();
181 }
182
183 void TextFieldInputType::forwardEvent(Event& event)
184 {
185     if (m_innerSpinButton) {
186         m_innerSpinButton->forwardEvent(event);
187         if (event.defaultHandled())
188             return;
189     }
190
191     bool isFocusEvent = event.type() == eventNames().focusEvent;
192     bool isBlurEvent = event.type() == eventNames().blurEvent;
193     if (isFocusEvent || isBlurEvent)
194         capsLockStateMayHaveChanged();
195     if (event.isMouseEvent() || isFocusEvent || isBlurEvent)
196         element().forwardEvent(event);
197 }
198
199 void TextFieldInputType::elementDidBlur()
200 {
201     auto* renderer = element().renderer();
202     if (!renderer)
203         return;
204
205     auto* innerTextRenderer = innerTextElement()->renderer();
206     if (!innerTextRenderer)
207         return;
208
209     auto* innerLayer = innerTextRenderer->layer();
210     if (!innerLayer)
211         return;
212
213     bool isLeftToRightDirection = downcast<RenderTextControlSingleLine>(*renderer).style().isLeftToRightDirection();
214     ScrollOffset scrollOffset(isLeftToRightDirection ? 0 : innerLayer->scrollWidth(), 0);
215     innerLayer->scrollToOffset(scrollOffset);
216 }
217
218 void TextFieldInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection)
219 {
220     ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != &element());
221     if (RefPtr<Frame> frame = element().document().frame())
222         frame->editor().textFieldDidBeginEditing(&element());
223 }
224
225 void TextFieldInputType::handleBlurEvent()
226 {
227     InputType::handleBlurEvent();
228     element().endEditing();
229 }
230
231 bool TextFieldInputType::shouldSubmitImplicitly(Event& event)
232 {
233     return (event.type() == eventNames().textInputEvent && is<TextEvent>(event) && downcast<TextEvent>(event).data() == "\n")
234         || InputType::shouldSubmitImplicitly(event);
235 }
236
237 RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(RenderStyle&& style)
238 {
239     return createRenderer<RenderTextControlSingleLine>(element(), WTFMove(style));
240 }
241
242 bool TextFieldInputType::needsContainer() const
243 {
244     return false;
245 }
246
247 bool TextFieldInputType::shouldHaveSpinButton() const
248 {
249     return RenderTheme::singleton().shouldHaveSpinButton(element());
250 }
251
252 bool TextFieldInputType::shouldHaveCapsLockIndicator() const
253 {
254     return RenderTheme::singleton().shouldHaveCapsLockIndicator(element());
255 }
256
257 void TextFieldInputType::createShadowSubtree()
258 {
259     ASSERT(element().shadowRoot());
260
261     ASSERT(!m_innerText);
262     ASSERT(!m_innerBlock);
263     ASSERT(!m_innerSpinButton);
264     ASSERT(!m_capsLockIndicator);
265     ASSERT(!m_autoFillButton);
266
267     Document& document = element().document();
268     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
269     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
270     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
271
272     m_innerText = TextControlInnerTextElement::create(document);
273
274     if (!createsContainer) {
275         element().userAgentShadowRoot()->appendChild(*m_innerText);
276         updatePlaceholderText();
277         return;
278     }
279
280     createContainer();
281     updatePlaceholderText();
282
283     if (shouldHaveSpinButton) {
284         m_innerSpinButton = SpinButtonElement::create(document, *this);
285         m_container->appendChild(*m_innerSpinButton);
286     }
287
288     if (shouldHaveCapsLockIndicator) {
289         m_capsLockIndicator = HTMLDivElement::create(document);
290         m_capsLockIndicator->setPseudo(AtomicString("-webkit-caps-lock-indicator", AtomicString::ConstructFromLiteral));
291
292         bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
293         m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
294
295         m_container->appendChild(*m_capsLockIndicator);
296     }
297
298     updateAutoFillButton();
299 }
300
301 HTMLElement* TextFieldInputType::containerElement() const
302 {
303     return m_container.get();
304 }
305
306 HTMLElement* TextFieldInputType::innerBlockElement() const
307 {
308     return m_innerBlock.get();
309 }
310
311 RefPtr<TextControlInnerTextElement> TextFieldInputType::innerTextElement() const
312 {
313     ASSERT(m_innerText);
314     return m_innerText;
315 }
316
317 HTMLElement* TextFieldInputType::innerSpinButtonElement() const
318 {
319     return m_innerSpinButton.get();
320 }
321
322 HTMLElement* TextFieldInputType::capsLockIndicatorElement() const
323 {
324     return m_capsLockIndicator.get();
325 }
326
327 HTMLElement* TextFieldInputType::autoFillButtonElement() const
328 {
329     return m_autoFillButton.get();
330 }
331
332 HTMLElement* TextFieldInputType::placeholderElement() const
333 {
334     return m_placeholder.get();
335 }
336
337 void TextFieldInputType::destroyShadowSubtree()
338 {
339     InputType::destroyShadowSubtree();
340     m_innerText = nullptr;
341     m_placeholder = nullptr;
342     m_innerBlock = nullptr;
343     if (m_innerSpinButton)
344         m_innerSpinButton->removeSpinButtonOwner();
345     m_innerSpinButton = nullptr;
346     m_capsLockIndicator = nullptr;
347     m_autoFillButton = nullptr;
348     m_container = nullptr;
349 }
350
351 void TextFieldInputType::attributeChanged(const QualifiedName& attributeName)
352 {
353     if (attributeName == valueAttr || attributeName == placeholderAttr)
354         updateInnerTextValue();
355 }
356
357 void TextFieldInputType::disabledAttributeChanged()
358 {
359     if (m_innerSpinButton)
360         m_innerSpinButton->releaseCapture();
361     capsLockStateMayHaveChanged();
362     updateAutoFillButton();
363 }
364
365 void TextFieldInputType::readonlyAttributeChanged()
366 {
367     if (m_innerSpinButton)
368         m_innerSpinButton->releaseCapture();
369     capsLockStateMayHaveChanged();
370     updateAutoFillButton();
371 }
372
373 bool TextFieldInputType::supportsReadOnly() const
374 {
375     return true;
376 }
377
378 bool TextFieldInputType::shouldUseInputMethod() const
379 {
380     return true;
381 }
382
383 // FIXME: The name of this function doesn't make clear the two jobs it does:
384 // 1) Limits the string to a particular number of grapheme clusters.
385 // 2) Truncates the string at the first character which is a control character other than tab.
386 // FIXME: TextFieldInputType::sanitizeValue doesn't need a limit on grapheme clusters. A limit on code units would do.
387 // FIXME: Where does the "truncate at first control character" rule come from?
388 static String limitLength(const String& string, unsigned maxNumGraphemeClusters)
389 {
390     StringView stringView { string };
391     unsigned firstNonTabControlCharacterIndex = stringView.find([] (UChar character) {
392         return character < ' ' && character != '\t';
393     });
394     unsigned limitedLength;
395     if (stringView.is8Bit())
396         limitedLength = std::min(firstNonTabControlCharacterIndex, maxNumGraphemeClusters);
397     else
398         limitedLength = numCharactersInGraphemeClusters(stringView.substring(0, firstNonTabControlCharacterIndex), maxNumGraphemeClusters);
399     return string.left(limitedLength);
400 }
401
402 static String autoFillButtonTypeToAccessibilityLabel(AutoFillButtonType autoFillButtonType)
403 {
404     switch (autoFillButtonType) {
405     case AutoFillButtonType::Contacts:
406         return AXAutoFillContactsLabel();
407     case AutoFillButtonType::Credentials:
408         return AXAutoFillCredentialsLabel();
409     default:
410     case AutoFillButtonType::None:
411         ASSERT_NOT_REACHED();
412         return String();
413     }
414 }
415     
416 static AtomicString autoFillButtonTypeToAutoFillButtonPseudoClassName(AutoFillButtonType autoFillButtonType)
417 {
418     AtomicString pseudoClassName;
419     switch (autoFillButtonType) {
420     case AutoFillButtonType::Contacts:
421         pseudoClassName = AtomicString("-webkit-contacts-auto-fill-button", AtomicString::ConstructFromLiteral);
422         break;
423     case AutoFillButtonType::Credentials:
424         pseudoClassName = AtomicString("-webkit-credentials-auto-fill-button", AtomicString::ConstructFromLiteral);
425         break;
426     case AutoFillButtonType::None:
427         ASSERT_NOT_REACHED();
428         break;
429     }
430
431     return pseudoClassName;
432 }
433
434 static bool isAutoFillButtonTypeChanged(const AtomicString& attribute, AutoFillButtonType autoFillButtonType)
435 {
436     if (attribute == "-webkit-contacts-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Contacts)
437         return true;
438
439     if (attribute == "-webkit-credentials-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Credentials)
440         return true;
441
442     return false;
443 }
444
445 String TextFieldInputType::sanitizeValue(const String& proposedValue) const
446 {
447     return limitLength(proposedValue.removeCharacters(isHTMLLineBreak), HTMLInputElement::maxEffectiveLength);
448 }
449
450 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent& event)
451 {
452     // Make sure that the text to be inserted will not violate the maxLength.
453
454     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
455     // because they can be mismatched by sanitizeValue() in
456     // HTMLInputElement::subtreeHasChanged() in some cases.
457     String innerText = element().innerTextValue();
458     unsigned oldLength = numGraphemeClusters(innerText);
459
460     // selectionLength represents the selection length of this text field to be
461     // removed by this insertion.
462     // If the text field has no focus, we don't need to take account of the
463     // selection length. The selection is the source of text drag-and-drop in
464     // that case, and nothing in the text field will be removed.
465     unsigned selectionLength = 0;
466     if (element().focused()) {
467         ASSERT(enclosingTextFormControl(element().document().frame()->selection().selection().start()) == &element());
468         int selectionStart = element().selectionStart();
469         ASSERT(selectionStart <= element().selectionEnd());
470         int selectionCodeUnitCount = element().selectionEnd() - selectionStart;
471         selectionLength = selectionCodeUnitCount ? numGraphemeClusters(StringView(innerText).substring(selectionStart, selectionCodeUnitCount)) : 0;
472     }
473     ASSERT(oldLength >= selectionLength);
474
475     // Selected characters will be removed by the next text event.
476     unsigned baseLength = oldLength - selectionLength;
477     unsigned maxLength = isTextType() ? element().effectiveMaxLength() : HTMLInputElement::maxEffectiveLength;
478     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
479
480     // Truncate the inserted text to avoid violating the maxLength and other constraints.
481     String eventText = event.text();
482     unsigned textLength = eventText.length();
483     while (textLength > 0 && isHTMLLineBreak(eventText[textLength - 1]))
484         textLength--;
485     eventText.truncate(textLength);
486     eventText.replace("\r\n", " ");
487     eventText.replace('\r', ' ');
488     eventText.replace('\n', ' ');
489     event.setText(limitLength(eventText, appendableLength));
490 }
491
492 bool TextFieldInputType::shouldRespectListAttribute()
493 {
494     return InputType::themeSupportsDataListUI(this);
495 }
496
497 void TextFieldInputType::updatePlaceholderText()
498 {
499     if (!supportsPlaceholder())
500         return;
501     String placeholderText = element().strippedPlaceholder();
502     if (placeholderText.isEmpty()) {
503         if (m_placeholder) {
504             m_placeholder->parentNode()->removeChild(*m_placeholder);
505             m_placeholder = nullptr;
506         }
507         return;
508     }
509     if (!m_placeholder) {
510         m_placeholder = TextControlPlaceholderElement::create(element().document());
511         element().userAgentShadowRoot()->insertBefore(*m_placeholder, m_container ? m_container.get() : innerTextElement().get());
512     }
513     m_placeholder->setInnerText(placeholderText);
514 }
515
516 bool TextFieldInputType::appendFormData(DOMFormData& formData, bool multipart) const
517 {
518     InputType::appendFormData(formData, multipart);
519     auto& dirnameAttrValue = element().attributeWithoutSynchronization(dirnameAttr);
520     if (!dirnameAttrValue.isNull())
521         formData.append(dirnameAttrValue, element().directionForFormData());
522     return true;
523 }
524
525 String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
526 {
527     return visibleValue;
528 }
529
530 void TextFieldInputType::subtreeHasChanged()
531 {
532     element().setChangedSinceLastFormControlChangeEvent(true);
533
534     // We don't need to call sanitizeUserInputValue() function here because
535     // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
536     // sanitizeUserInputValue().
537     // ---
538     // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
539     // ---
540     // Input types that support the selection API do *not* sanitize their
541     // user input in order to retain parity between what's in the model and
542     // what's on the screen. Otherwise, we retain the sanitization process for
543     // backward compatibility. https://bugs.webkit.org/show_bug.cgi?id=150346
544     String innerText = convertFromVisibleValue(element().innerTextValue());
545     if (!supportsSelectionAPI())
546         innerText = sanitizeValue(innerText);
547     element().setValueFromRenderer(innerText);
548     element().updatePlaceholderVisibility();
549     // Recalc for :invalid change.
550     element().invalidateStyleForSubtree();
551
552     didSetValueByUserEdit();
553 }
554
555 void TextFieldInputType::didSetValueByUserEdit()
556 {
557     if (!element().focused())
558         return;
559     if (RefPtr<Frame> frame = element().document().frame())
560         frame->editor().textDidChangeInTextField(&element());
561 }
562
563 void TextFieldInputType::spinButtonStepDown()
564 {
565     stepUpFromRenderer(-1);
566 }
567
568 void TextFieldInputType::spinButtonStepUp()
569 {
570     stepUpFromRenderer(1);
571 }
572
573 void TextFieldInputType::updateInnerTextValue()
574 {
575     if (!element().formControlValueMatchesRenderer()) {
576         // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
577         // It protects an unacceptable renderer value from being overwritten with the DOM value.
578         element().setInnerTextValue(visibleValue());
579         element().updatePlaceholderVisibility();
580     }
581 }
582
583 void TextFieldInputType::focusAndSelectSpinButtonOwner()
584 {
585     Ref<HTMLInputElement> input(element());
586     input->focus();
587     input->select();
588 }
589
590 bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
591 {
592     return !element().isDisabledOrReadOnly();
593 }
594
595 bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
596 {
597     return shouldSpinButtonRespondToMouseEvents() && element().focused();
598 }
599
600 bool TextFieldInputType::shouldDrawCapsLockIndicator() const
601 {
602     if (element().document().focusedElement() != &element())
603         return false;
604
605     if (element().isDisabledOrReadOnly())
606         return false;
607
608     RefPtr<Frame> frame = element().document().frame();
609     if (!frame)
610         return false;
611
612     if (!frame->selection().isFocusedAndActive())
613         return false;
614
615     return PlatformKeyboardEvent::currentCapsLockState();
616 }
617
618 void TextFieldInputType::capsLockStateMayHaveChanged()
619 {
620     if (!m_capsLockIndicator)
621         return;
622
623     bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
624     m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
625 }
626
627 bool TextFieldInputType::shouldDrawAutoFillButton() const
628 {
629     return !element().isDisabledOrReadOnly() && element().autoFillButtonType() != AutoFillButtonType::None;
630 }
631
632 void TextFieldInputType::autoFillButtonElementWasClicked()
633 {
634     Page* page = element().document().page();
635     if (!page)
636         return;
637
638     page->chrome().client().handleAutoFillButtonClick(element());
639 }
640
641 void TextFieldInputType::createContainer()
642 {
643     ASSERT(!m_container);
644
645     m_container = TextControlInnerContainer::create(element().document());
646     m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
647
648     m_innerBlock = TextControlInnerElement::create(element().document());
649     m_innerBlock->appendChild(*m_innerText);
650     m_container->appendChild(*m_innerBlock);
651
652     element().userAgentShadowRoot()->appendChild(*m_container);
653 }
654
655 void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonType)
656 {
657     ASSERT(!m_autoFillButton);
658
659     if (autoFillButtonType == AutoFillButtonType::None)
660         return;
661
662     m_autoFillButton = AutoFillButtonElement::create(element().document(), *this);
663     m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
664     m_autoFillButton->setAttributeWithoutSynchronization(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
665     m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
666     m_container->appendChild(*m_autoFillButton);
667 }
668
669 void TextFieldInputType::updateAutoFillButton()
670 {
671     if (shouldDrawAutoFillButton()) {
672         if (!m_container)
673             createContainer();
674
675         if (!m_autoFillButton)
676             createAutoFillButton(element().autoFillButtonType());
677
678         const AtomicString& attribute = m_autoFillButton->attributeWithoutSynchronization(pseudoAttr);
679         bool shouldUpdateAutoFillButtonType = isAutoFillButtonTypeChanged(attribute, element().autoFillButtonType());
680         if (shouldUpdateAutoFillButtonType) {
681             m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(element().autoFillButtonType()));
682             m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(element().autoFillButtonType()));
683         }
684         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock, true);
685         return;
686     }
687     
688     if (m_autoFillButton)
689         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);        
690 }
691
692 } // namespace WebCore