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