Use emptyString() / nullAtom when possible
[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 "Editor.h"
39 #include "EventNames.h"
40 #include "FormDataList.h"
41 #include "Frame.h"
42 #include "FrameSelection.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLNames.h"
45 #include "KeyboardEvent.h"
46 #include "LocalizedStrings.h"
47 #include "NodeRenderStyle.h"
48 #include "Page.h"
49 #include "PlatformKeyboardEvent.h"
50 #include "RenderLayer.h"
51 #include "RenderTextControlSingleLine.h"
52 #include "RenderTheme.h"
53 #include "ShadowRoot.h"
54 #include <wtf/text/TextBreakIterator.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     TextControlInnerTextElement* innerText = innerTextElement();
98     ASSERT(innerText);
99
100     for (Text* text = TextNodeTraversal::firstWithin(*innerText); text; text = TextNodeTraversal::next(*text, innerText)) {
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     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     if (event->isMouseEvent()
192         || event->type() == eventNames().blurEvent
193         || event->type() == eventNames().focusEvent)
194     {
195         element().document().updateStyleIfNeeded();
196
197         auto* renderer = element().renderer();
198         if (element().renderer()) {
199             if (event->type() == eventNames().blurEvent) {
200                 if (auto* innerTextRenderer = innerTextElement()->renderer()) {
201                     if (auto* innerLayer = innerTextRenderer->layer()) {
202                         bool isLeftToRightDirection = downcast<RenderTextControlSingleLine>(*renderer).style().isLeftToRightDirection();
203                         ScrollOffset scrollOffset(isLeftToRightDirection ? 0 : innerLayer->scrollWidth(), 0);
204                         innerLayer->scrollToOffset(scrollOffset, RenderLayer::ScrollOffsetClamped);
205                     }
206                 }
207                 capsLockStateMayHaveChanged();
208             } else if (event->type() == eventNames().focusEvent)
209                 capsLockStateMayHaveChanged();
210
211             element().forwardEvent(event);
212         }
213     }
214 }
215
216 void TextFieldInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection)
217 {
218     ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != &element());
219     if (Frame* frame = element().document().frame())
220         frame->editor().textFieldDidBeginEditing(&element());
221 }
222
223 void TextFieldInputType::handleBlurEvent()
224 {
225     InputType::handleBlurEvent();
226     element().endEditing();
227 }
228
229 bool TextFieldInputType::shouldSubmitImplicitly(Event* event)
230 {
231     return (event->type() == eventNames().textInputEvent && is<TextEvent>(*event) && downcast<TextEvent>(*event).data() == "\n")
232         || InputType::shouldSubmitImplicitly(event);
233 }
234
235 RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(RenderStyle&& style)
236 {
237     return createRenderer<RenderTextControlSingleLine>(element(), WTFMove(style));
238 }
239
240 bool TextFieldInputType::needsContainer() const
241 {
242     return false;
243 }
244
245 bool TextFieldInputType::shouldHaveSpinButton() const
246 {
247     Document& document = element().document();
248     RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme();
249     return theme->shouldHaveSpinButton(element());
250 }
251
252 bool TextFieldInputType::shouldHaveCapsLockIndicator() const
253 {
254     Document& document = element().document();
255     RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme();
256     return theme->shouldHaveCapsLockIndicator(element());
257 }
258
259 void TextFieldInputType::createShadowSubtree()
260 {
261     ASSERT(element().shadowRoot());
262
263     ASSERT(!m_innerText);
264     ASSERT(!m_innerBlock);
265     ASSERT(!m_innerSpinButton);
266     ASSERT(!m_capsLockIndicator);
267     ASSERT(!m_autoFillButton);
268
269     Document& document = element().document();
270     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
271     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
272     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
273
274     m_innerText = TextControlInnerTextElement::create(document);
275
276     if (!createsContainer) {
277         element().userAgentShadowRoot()->appendChild(*m_innerText, IGNORE_EXCEPTION);
278         updatePlaceholderText();
279         return;
280     }
281
282     createContainer();
283     updatePlaceholderText();
284
285     if (shouldHaveSpinButton) {
286         m_innerSpinButton = SpinButtonElement::create(document, *this);
287         m_container->appendChild(*m_innerSpinButton, IGNORE_EXCEPTION);
288     }
289
290     if (shouldHaveCapsLockIndicator) {
291         m_capsLockIndicator = HTMLDivElement::create(document);
292         m_capsLockIndicator->setPseudo(AtomicString("-webkit-caps-lock-indicator", AtomicString::ConstructFromLiteral));
293
294         bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
295         m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
296
297         m_container->appendChild(*m_capsLockIndicator, IGNORE_EXCEPTION);
298     }
299
300     updateAutoFillButton();
301 }
302
303 HTMLElement* TextFieldInputType::containerElement() const
304 {
305     return m_container.get();
306 }
307
308 HTMLElement* TextFieldInputType::innerBlockElement() const
309 {
310     return m_innerBlock.get();
311 }
312
313 TextControlInnerTextElement* TextFieldInputType::innerTextElement() const
314 {
315     ASSERT(m_innerText);
316     return m_innerText.get();
317 }
318
319 HTMLElement* TextFieldInputType::innerSpinButtonElement() const
320 {
321     return m_innerSpinButton.get();
322 }
323
324 HTMLElement* TextFieldInputType::capsLockIndicatorElement() const
325 {
326     return m_capsLockIndicator.get();
327 }
328
329 HTMLElement* TextFieldInputType::autoFillButtonElement() const
330 {
331     return m_autoFillButton.get();
332 }
333
334 HTMLElement* TextFieldInputType::placeholderElement() const
335 {
336     return m_placeholder.get();
337 }
338
339 void TextFieldInputType::destroyShadowSubtree()
340 {
341     InputType::destroyShadowSubtree();
342     m_innerText = nullptr;
343     m_placeholder = nullptr;
344     m_innerBlock = nullptr;
345     if (m_innerSpinButton)
346         m_innerSpinButton->removeSpinButtonOwner();
347     m_innerSpinButton = nullptr;
348     m_capsLockIndicator = nullptr;
349     m_autoFillButton = nullptr;
350     m_container = nullptr;
351 }
352
353 void TextFieldInputType::attributeChanged()
354 {
355     // FIXME: Updating the inner text on any attribute update should
356     // be unnecessary. We should figure out what attributes affect.
357     updateInnerTextValue();
358 }
359
360 void TextFieldInputType::disabledAttributeChanged()
361 {
362     if (m_innerSpinButton)
363         m_innerSpinButton->releaseCapture();
364     capsLockStateMayHaveChanged();
365     updateAutoFillButton();
366 }
367
368 void TextFieldInputType::readonlyAttributeChanged()
369 {
370     if (m_innerSpinButton)
371         m_innerSpinButton->releaseCapture();
372     capsLockStateMayHaveChanged();
373     updateAutoFillButton();
374 }
375
376 bool TextFieldInputType::supportsReadOnly() const
377 {
378     return true;
379 }
380
381 bool TextFieldInputType::shouldUseInputMethod() const
382 {
383     return true;
384 }
385
386 static bool isASCIILineBreak(UChar c)
387 {
388     return c == '\r' || c == '\n';
389 }
390
391 static String limitLength(const String& string, int maxLength)
392 {
393     unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
394     for (unsigned i = 0; i < newLength; ++i) {
395         const UChar current = string[i];
396         if (current < ' ' && current != '\t') {
397             newLength = i;
398             break;
399         }
400     }
401     return string.left(newLength);
402 }
403
404 static String autoFillButtonTypeToAccessibilityLabel(AutoFillButtonType autoFillButtonType)
405 {
406     switch (autoFillButtonType) {
407     case AutoFillButtonType::Contacts:
408         return AXAutoFillContactsLabel();
409     case AutoFillButtonType::Credentials:
410         return AXAutoFillCredentialsLabel();
411     default:
412     case AutoFillButtonType::None:
413         ASSERT_NOT_REACHED();
414         return String();
415     }
416 }
417     
418 static AtomicString autoFillButtonTypeToAutoFillButtonPseudoClassName(AutoFillButtonType autoFillButtonType)
419 {
420     AtomicString pseudoClassName;
421     switch (autoFillButtonType) {
422     case AutoFillButtonType::Contacts:
423         pseudoClassName = AtomicString("-webkit-contacts-auto-fill-button", AtomicString::ConstructFromLiteral);
424         break;
425     case AutoFillButtonType::Credentials:
426         pseudoClassName = AtomicString("-webkit-credentials-auto-fill-button", AtomicString::ConstructFromLiteral);
427         break;
428     case AutoFillButtonType::None:
429         ASSERT_NOT_REACHED();
430         break;
431     }
432
433     return pseudoClassName;
434 }
435
436 static bool isAutoFillButtonTypeChanged(const AtomicString& attribute, AutoFillButtonType autoFillButtonType)
437 {
438     if (attribute == "-webkit-contacts-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Contacts)
439         return true;
440
441     if (attribute == "-webkit-credentials-auto-fill-button" && autoFillButtonType != AutoFillButtonType::Credentials)
442         return true;
443
444     return false;
445 }
446
447 String TextFieldInputType::sanitizeValue(const String& proposedValue) const
448 {
449     return limitLength(proposedValue.removeCharacters(isASCIILineBreak), HTMLInputElement::maxEffectiveLength);
450 }
451
452 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
453 {
454     // Make sure that the text to be inserted will not violate the maxLength.
455
456     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
457     // because they can be mismatched by sanitizeValue() in
458     // HTMLInputElement::subtreeHasChanged() in some cases.
459     String innerText = element().innerTextValue();
460     unsigned oldLength = numGraphemeClusters(innerText);
461
462     // selectionLength represents the selection length of this text field to be
463     // removed by this insertion.
464     // If the text field has no focus, we don't need to take account of the
465     // selection length. The selection is the source of text drag-and-drop in
466     // that case, and nothing in the text field will be removed.
467     unsigned selectionLength = 0;
468     if (element().focused()) {
469         ASSERT(enclosingTextFormControl(element().document().frame()->selection().selection().start()) == &element());
470         int selectionStart = element().selectionStart();
471         ASSERT(selectionStart <= element().selectionEnd());
472         int selectionCodeUnitCount = element().selectionEnd() - selectionStart;
473         selectionLength = selectionCodeUnitCount ? numGraphemeClusters(innerText.substring(selectionStart, selectionCodeUnitCount)) : 0;
474     }
475     ASSERT(oldLength >= selectionLength);
476
477     // Selected characters will be removed by the next text event.
478     unsigned baseLength = oldLength - selectionLength;
479     unsigned maxLength = isTextType() ? element().effectiveMaxLength() : HTMLInputElement::maxEffectiveLength;
480     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
481
482     // Truncate the inserted text to avoid violating the maxLength and other constraints.
483     String eventText = event->text();
484     unsigned textLength = eventText.length();
485     while (textLength > 0 && isASCIILineBreak(eventText[textLength - 1]))
486         textLength--;
487     eventText.truncate(textLength);
488     eventText.replace("\r\n", " ");
489     eventText.replace('\r', ' ');
490     eventText.replace('\n', ' ');
491
492     event->setText(limitLength(eventText, appendableLength));
493 }
494
495 bool TextFieldInputType::shouldRespectListAttribute()
496 {
497     return InputType::themeSupportsDataListUI(this);
498 }
499
500 void TextFieldInputType::updatePlaceholderText()
501 {
502     if (!supportsPlaceholder())
503         return;
504     String placeholderText = element().strippedPlaceholder();
505     if (placeholderText.isEmpty()) {
506         if (m_placeholder) {
507             m_placeholder->parentNode()->removeChild(*m_placeholder, ASSERT_NO_EXCEPTION);
508             m_placeholder = nullptr;
509         }
510         return;
511     }
512     if (!m_placeholder) {
513         m_placeholder = TextControlPlaceholderElement::create(element().document());
514         element().userAgentShadowRoot()->insertBefore(*m_placeholder, m_container ? m_container.get() : innerTextElement(), ASSERT_NO_EXCEPTION);        
515     }
516     m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION);
517 }
518
519 bool TextFieldInputType::appendFormData(FormDataList& list, bool multipart) const
520 {
521     InputType::appendFormData(list, multipart);
522     const AtomicString& dirnameAttrValue = element().fastGetAttribute(dirnameAttr);
523     if (!dirnameAttrValue.isNull())
524         list.appendData(dirnameAttrValue, element().directionForFormData());
525     return true;
526 }
527
528 String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
529 {
530     return visibleValue;
531 }
532
533 void TextFieldInputType::subtreeHasChanged()
534 {
535     element().setChangedSinceLastFormControlChangeEvent(true);
536
537     // We don't need to call sanitizeUserInputValue() function here because
538     // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
539     // sanitizeUserInputValue().
540     // ---
541     // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
542     // ---
543     // Input types that support the selection API do *not* sanitize their
544     // user input in order to retain parity between what's in the model and
545     // what's on the screen. Otherwise, we retain the sanitization process for
546     // backward compatibility. https://bugs.webkit.org/show_bug.cgi?id=150346
547     String innerText = convertFromVisibleValue(element().innerTextValue());
548     if (!supportsSelectionAPI())
549         innerText = sanitizeValue(innerText);
550     element().setValueFromRenderer(innerText);
551     element().updatePlaceholderVisibility();
552     // Recalc for :invalid change.
553     element().setNeedsStyleRecalc();
554
555     didSetValueByUserEdit();
556 }
557
558 void TextFieldInputType::didSetValueByUserEdit()
559 {
560     if (!element().focused())
561         return;
562     if (Frame* frame = element().document().frame())
563         frame->editor().textDidChangeInTextField(&element());
564 }
565
566 void TextFieldInputType::spinButtonStepDown()
567 {
568     stepUpFromRenderer(-1);
569 }
570
571 void TextFieldInputType::spinButtonStepUp()
572 {
573     stepUpFromRenderer(1);
574 }
575
576 void TextFieldInputType::updateInnerTextValue()
577 {
578     if (!element().formControlValueMatchesRenderer()) {
579         // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
580         // It protects an unacceptable renderer value from being overwritten with the DOM value.
581         element().setInnerTextValue(visibleValue());
582         element().updatePlaceholderVisibility();
583     }
584 }
585
586 void TextFieldInputType::focusAndSelectSpinButtonOwner()
587 {
588     Ref<HTMLInputElement> input(element());
589     input->focus();
590     input->select();
591 }
592
593 bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
594 {
595     return !element().isDisabledOrReadOnly();
596 }
597
598 bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
599 {
600     return shouldSpinButtonRespondToMouseEvents() && element().focused();
601 }
602
603 bool TextFieldInputType::shouldDrawCapsLockIndicator() const
604 {
605     if (element().document().focusedElement() != &element())
606         return false;
607
608     if (element().isDisabledOrReadOnly())
609         return false;
610
611     Frame* frame = element().document().frame();
612     if (!frame)
613         return false;
614
615     if (!frame->selection().isFocusedAndActive())
616         return false;
617
618     return PlatformKeyboardEvent::currentCapsLockState();
619 }
620
621 void TextFieldInputType::capsLockStateMayHaveChanged()
622 {
623     if (!m_capsLockIndicator)
624         return;
625
626     bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
627     m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
628 }
629
630 bool TextFieldInputType::shouldDrawAutoFillButton() const
631 {
632     return !element().isDisabledOrReadOnly() && element().autoFillButtonType() != AutoFillButtonType::None;
633 }
634
635 void TextFieldInputType::autoFillButtonElementWasClicked()
636 {
637     Page* page = element().document().page();
638     if (!page)
639         return;
640
641     page->chrome().client().handleAutoFillButtonClick(element());
642 }
643
644 void TextFieldInputType::createContainer()
645 {
646     ASSERT(!m_container);
647
648     m_container = TextControlInnerContainer::create(element().document());
649     m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
650
651     m_innerBlock = TextControlInnerElement::create(element().document());
652     m_innerBlock->appendChild(*m_innerText, IGNORE_EXCEPTION);
653     m_container->appendChild(*m_innerBlock, IGNORE_EXCEPTION);
654
655     element().userAgentShadowRoot()->appendChild(*m_container, IGNORE_EXCEPTION);
656 }
657
658 void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonType)
659 {
660     ASSERT(!m_autoFillButton);
661
662     if (autoFillButtonType == AutoFillButtonType::None)
663         return;
664
665     m_autoFillButton = AutoFillButtonElement::create(element().document(), *this);
666     m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
667     m_autoFillButton->setAttributeWithoutSynchronization(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
668     m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
669     m_container->appendChild(*m_autoFillButton, IGNORE_EXCEPTION);
670 }
671
672 void TextFieldInputType::updateAutoFillButton()
673 {
674     if (shouldDrawAutoFillButton()) {
675         if (!m_container)
676             createContainer();
677
678         if (!m_autoFillButton)
679             createAutoFillButton(element().autoFillButtonType());
680
681         const AtomicString& attribute = m_autoFillButton->fastGetAttribute(pseudoAttr);
682         bool shouldUpdateAutoFillButtonType = isAutoFillButtonTypeChanged(attribute, element().autoFillButtonType());
683         if (shouldUpdateAutoFillButtonType) {
684             m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(element().autoFillButtonType()));
685             m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(element().autoFillButtonType()));
686         }
687         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock, true);
688         return;
689     }
690     
691     if (m_autoFillButton)
692         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);        
693 }
694
695 } // namespace WebCore