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