AX: AutoFill button is not accessible with VoiceOver
[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->isDragEvent()
192         || event->eventInterface() == WheelEventInterfaceType
193         || event->type() == eventNames().blurEvent
194         || event->type() == eventNames().focusEvent)
195     {
196         element().document().updateStyleIfNeeded();
197
198         if (element().renderer()) {
199             RenderTextControlSingleLine& renderTextControl = downcast<RenderTextControlSingleLine>(*element().renderer());
200             if (event->type() == eventNames().blurEvent) {
201                 if (RenderTextControlInnerBlock* innerTextRenderer = innerTextElement()->renderer()) {
202                     if (RenderLayer* innerLayer = innerTextRenderer->layer()) {
203                         IntSize scrollOffset(!renderTextControl.style().isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0);
204                         innerLayer->scrollToOffset(scrollOffset, RenderLayer::ScrollOffsetClamped);
205                     }
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::handleBlurEvent()
218 {
219     InputType::handleBlurEvent();
220     element().endEditing();
221 }
222
223 bool TextFieldInputType::shouldSubmitImplicitly(Event* event)
224 {
225     return (event->type() == eventNames().textInputEvent && is<TextEvent>(*event) && downcast<TextEvent>(*event).data() == "\n")
226         || InputType::shouldSubmitImplicitly(event);
227 }
228
229 RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(Ref<RenderStyle>&& style)
230 {
231     return createRenderer<RenderTextControlSingleLine>(element(), WTF::move(style));
232 }
233
234 bool TextFieldInputType::needsContainer() const
235 {
236     return false;
237 }
238
239 bool TextFieldInputType::shouldHaveSpinButton() const
240 {
241     Document& document = element().document();
242     RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme();
243     return theme->shouldHaveSpinButton(element());
244 }
245
246 bool TextFieldInputType::shouldHaveCapsLockIndicator() const
247 {
248     Document& document = element().document();
249     RefPtr<RenderTheme> theme = document.page() ? &document.page()->theme() : RenderTheme::defaultTheme();
250     return theme->shouldHaveCapsLockIndicator(element());
251 }
252
253 void TextFieldInputType::createShadowSubtree()
254 {
255     ASSERT(element().shadowRoot());
256
257     ASSERT(!m_innerText);
258     ASSERT(!m_innerBlock);
259     ASSERT(!m_innerSpinButton);
260     ASSERT(!m_capsLockIndicator);
261     ASSERT(!m_autoFillButton);
262
263     Document& document = element().document();
264     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
265     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
266     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
267
268     m_innerText = TextControlInnerTextElement::create(document);
269
270     if (!createsContainer) {
271         element().userAgentShadowRoot()->appendChild(m_innerText, IGNORE_EXCEPTION);
272         updatePlaceholderText();
273         return;
274     }
275
276     createContainer();
277     updatePlaceholderText();
278
279     if (shouldHaveSpinButton) {
280         m_innerSpinButton = SpinButtonElement::create(document, *this);
281         m_container->appendChild(m_innerSpinButton, IGNORE_EXCEPTION);
282     }
283
284     if (shouldHaveCapsLockIndicator) {
285         m_capsLockIndicator = HTMLDivElement::create(document);
286         m_capsLockIndicator->setPseudo(AtomicString("-webkit-caps-lock-indicator", AtomicString::ConstructFromLiteral));
287
288         bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
289         m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
290
291         m_container->appendChild(m_capsLockIndicator, IGNORE_EXCEPTION);
292     }
293
294     updateAutoFillButton();
295 }
296
297 HTMLElement* TextFieldInputType::containerElement() const
298 {
299     return m_container.get();
300 }
301
302 HTMLElement* TextFieldInputType::innerBlockElement() const
303 {
304     return m_innerBlock.get();
305 }
306
307 TextControlInnerTextElement* TextFieldInputType::innerTextElement() const
308 {
309     ASSERT(m_innerText);
310     return m_innerText.get();
311 }
312
313 HTMLElement* TextFieldInputType::innerSpinButtonElement() const
314 {
315     return m_innerSpinButton.get();
316 }
317
318 HTMLElement* TextFieldInputType::capsLockIndicatorElement() const
319 {
320     return m_capsLockIndicator.get();
321 }
322
323 HTMLElement* TextFieldInputType::autoFillButtonElement() const
324 {
325     return m_autoFillButton.get();
326 }
327
328 HTMLElement* TextFieldInputType::placeholderElement() const
329 {
330     return m_placeholder.get();
331 }
332
333 void TextFieldInputType::destroyShadowSubtree()
334 {
335     InputType::destroyShadowSubtree();
336     m_innerText = nullptr;
337     m_placeholder = nullptr;
338     m_innerBlock = nullptr;
339     if (m_innerSpinButton)
340         m_innerSpinButton->removeSpinButtonOwner();
341     m_innerSpinButton = nullptr;
342     m_capsLockIndicator = nullptr;
343     m_autoFillButton = nullptr;
344     m_container = nullptr;
345 }
346
347 void TextFieldInputType::attributeChanged()
348 {
349     // FIXME: Updating the inner text on any attribute update should
350     // be unnecessary. We should figure out what attributes affect.
351     updateInnerTextValue();
352 }
353
354 void TextFieldInputType::disabledAttributeChanged()
355 {
356     if (m_innerSpinButton)
357         m_innerSpinButton->releaseCapture();
358 }
359
360 void TextFieldInputType::readonlyAttributeChanged()
361 {
362     if (m_innerSpinButton)
363         m_innerSpinButton->releaseCapture();
364 }
365
366 bool TextFieldInputType::supportsReadOnly() const
367 {
368     return true;
369 }
370
371 bool TextFieldInputType::shouldUseInputMethod() const
372 {
373     return true;
374 }
375
376 static bool isASCIILineBreak(UChar c)
377 {
378     return c == '\r' || c == '\n';
379 }
380
381 static String limitLength(const String& string, int maxLength)
382 {
383     unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
384     for (unsigned i = 0; i < newLength; ++i) {
385         const UChar current = string[i];
386         if (current < ' ' && current != '\t') {
387             newLength = i;
388             break;
389         }
390     }
391     return string.left(newLength);
392 }
393
394 String TextFieldInputType::sanitizeValue(const String& proposedValue) const
395 {
396     return limitLength(proposedValue.removeCharacters(isASCIILineBreak), HTMLInputElement::maximumLength);
397 }
398
399 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
400 {
401     // Make sure that the text to be inserted will not violate the maxLength.
402
403     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
404     // because they can be mismatched by sanitizeValue() in
405     // HTMLInputElement::subtreeHasChanged() in some cases.
406     String innerText = element().innerTextValue();
407     unsigned oldLength = numGraphemeClusters(innerText);
408
409     // selectionLength represents the selection length of this text field to be
410     // removed by this insertion.
411     // If the text field has no focus, we don't need to take account of the
412     // selection length. The selection is the source of text drag-and-drop in
413     // that case, and nothing in the text field will be removed.
414     unsigned selectionLength = 0;
415     if (element().focused()) {
416         ASSERT(enclosingTextFormControl(element().document().frame()->selection().selection().start()) == &element());
417         int selectionStart = element().selectionStart();
418         ASSERT(selectionStart <= element().selectionEnd());
419         int selectionCodeUnitCount = element().selectionEnd() - selectionStart;
420         selectionLength = selectionCodeUnitCount ? numGraphemeClusters(innerText.substring(selectionStart, selectionCodeUnitCount)) : 0;
421     }
422     ASSERT(oldLength >= selectionLength);
423
424     // Selected characters will be removed by the next text event.
425     unsigned baseLength = oldLength - selectionLength;
426     unsigned maxLength = static_cast<unsigned>(isTextType() ? element().maxLength() : HTMLInputElement::maximumLength); // maxLength can never be negative.
427     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
428
429     // Truncate the inserted text to avoid violating the maxLength and other constraints.
430     String eventText = event->text();
431     unsigned textLength = eventText.length();
432     while (textLength > 0 && isASCIILineBreak(eventText[textLength - 1]))
433         textLength--;
434     eventText.truncate(textLength);
435     eventText.replace("\r\n", " ");
436     eventText.replace('\r', ' ');
437     eventText.replace('\n', ' ');
438
439     event->setText(limitLength(eventText, appendableLength));
440 }
441
442 bool TextFieldInputType::shouldRespectListAttribute()
443 {
444     return InputType::themeSupportsDataListUI(this);
445 }
446
447 void TextFieldInputType::updatePlaceholderText()
448 {
449     if (!supportsPlaceholder())
450         return;
451     String placeholderText = element().strippedPlaceholder();
452     if (placeholderText.isEmpty()) {
453         if (m_placeholder) {
454             m_placeholder->parentNode()->removeChild(m_placeholder.get(), ASSERT_NO_EXCEPTION);
455             m_placeholder.clear();
456         }
457         return;
458     }
459     if (!m_placeholder) {
460         m_placeholder = HTMLDivElement::create(element().document());
461         m_placeholder->setPseudo(AtomicString("-webkit-input-placeholder", AtomicString::ConstructFromLiteral));
462         m_placeholder->setInlineStyleProperty(CSSPropertyDisplay, element().isPlaceholderVisible() ? CSSValueBlock : CSSValueNone, true);
463         element().userAgentShadowRoot()->insertBefore(m_placeholder, m_container ? m_container.get() : innerTextElement(), ASSERT_NO_EXCEPTION);
464         
465     }
466     m_placeholder->setInnerText(placeholderText, ASSERT_NO_EXCEPTION);
467 }
468
469 bool TextFieldInputType::appendFormData(FormDataList& list, bool multipart) const
470 {
471     InputType::appendFormData(list, multipart);
472     const AtomicString& dirnameAttrValue = element().fastGetAttribute(dirnameAttr);
473     if (!dirnameAttrValue.isNull())
474         list.appendData(dirnameAttrValue, element().directionForFormData());
475     return true;
476 }
477
478 String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
479 {
480     return visibleValue;
481 }
482
483 void TextFieldInputType::subtreeHasChanged()
484 {
485     bool wasChanged = element().wasChangedSinceLastFormControlChangeEvent();
486     element().setChangedSinceLastFormControlChangeEvent(true);
487
488     // We don't need to call sanitizeUserInputValue() function here because
489     // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
490     // sanitizeUserInputValue().
491     // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
492     element().setValueFromRenderer(sanitizeValue(convertFromVisibleValue(element().innerTextValue())));
493     element().updatePlaceholderVisibility();
494     // Recalc for :invalid change.
495     element().setNeedsStyleRecalc();
496
497     didSetValueByUserEdit(wasChanged ? ValueChangeStateChanged : ValueChangeStateNone);
498 }
499
500 void TextFieldInputType::didSetValueByUserEdit(ValueChangeState state)
501 {
502     if (!element().focused())
503         return;
504     if (Frame* frame = element().document().frame()) {
505         if (state == ValueChangeStateNone)
506             frame->editor().textFieldDidBeginEditing(&element());
507         frame->editor().textDidChangeInTextField(&element());
508     }
509 }
510
511 void TextFieldInputType::spinButtonStepDown()
512 {
513     stepUpFromRenderer(-1);
514 }
515
516 void TextFieldInputType::spinButtonStepUp()
517 {
518     stepUpFromRenderer(1);
519 }
520
521 void TextFieldInputType::updateInnerTextValue()
522 {
523     if (!element().formControlValueMatchesRenderer()) {
524         // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
525         // It protects an unacceptable renderer value from being overwritten with the DOM value.
526         element().setInnerTextValue(visibleValue());
527         element().updatePlaceholderVisibility();
528     }
529 }
530
531 void TextFieldInputType::focusAndSelectSpinButtonOwner()
532 {
533     Ref<HTMLInputElement> input(element());
534     input->focus();
535     input->select();
536 }
537
538 bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
539 {
540     return !element().isDisabledOrReadOnly();
541 }
542
543 bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
544 {
545     return shouldSpinButtonRespondToMouseEvents() && element().focused();
546 }
547
548 bool TextFieldInputType::shouldDrawCapsLockIndicator() const
549 {
550     if (element().document().focusedElement() != &element())
551         return false;
552
553     Frame* frame = element().document().frame();
554     if (!frame)
555         return false;
556
557     if (!frame->selection().isFocusedAndActive())
558         return false;
559
560     return PlatformKeyboardEvent::currentCapsLockState();
561 }
562
563 void TextFieldInputType::capsLockStateMayHaveChanged()
564 {
565     if (!m_capsLockIndicator)
566         return;
567
568     bool shouldDrawCapsLockIndicator = this->shouldDrawCapsLockIndicator();
569     m_capsLockIndicator->setInlineStyleProperty(CSSPropertyDisplay, shouldDrawCapsLockIndicator ? CSSValueBlock : CSSValueNone, true);
570 }
571
572 bool TextFieldInputType::shouldDrawAutoFillButton() const
573 {
574     return element().showAutoFillButton();
575 }
576
577 void TextFieldInputType::autoFillButtonElementWasClicked()
578 {
579     Page* page = element().document().page();
580     if (!page)
581         return;
582
583     page->chrome().client().handleAutoFillButtonClick(element());
584 }
585
586 void TextFieldInputType::createContainer()
587 {
588     ASSERT(!m_container);
589
590     m_container = TextControlInnerContainer::create(element().document());
591     m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
592
593     m_innerBlock = TextControlInnerElement::create(element().document());
594     m_innerBlock->appendChild(m_innerText, IGNORE_EXCEPTION);
595     m_container->appendChild(m_innerBlock, IGNORE_EXCEPTION);
596
597     element().userAgentShadowRoot()->appendChild(m_container, IGNORE_EXCEPTION);
598 }
599
600 void TextFieldInputType::createAutoFillButton()
601 {
602     ASSERT(!m_autoFillButton);
603
604     m_autoFillButton = AutoFillButtonElement::create(element().document(), *this);
605     m_autoFillButton->setPseudo(AtomicString("-webkit-auto-fill-button", AtomicString::ConstructFromLiteral));
606     m_autoFillButton->setAttribute(aria_labelAttr, AtomicString(AXAutoFillButtonText()));
607     m_autoFillButton->setAttribute(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
608     m_container->appendChild(m_autoFillButton, IGNORE_EXCEPTION);
609 }
610
611 void TextFieldInputType::updateAutoFillButton()
612 {
613     if (shouldDrawAutoFillButton()) {
614         if (!m_container)
615             createContainer();
616
617         if (!m_autoFillButton)
618             createAutoFillButton();
619
620         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock, true);
621         return;
622     }
623     
624     if (m_autoFillButton)
625         m_autoFillButton->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone, true);        
626 }
627
628 } // namespace WebCore