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