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