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