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