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