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