initial import
[vuplus_webkit] / 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 "Frame.h"
37 #include "HTMLInputElement.h"
38 #include "KeyboardEvent.h"
39 #include "Page.h"
40 #include "RenderLayer.h"
41 #include "RenderTextControlSingleLine.h"
42 #include "RenderTheme.h"
43 #include "ShadowRoot.h"
44 #include "TextControlInnerElements.h"
45 #include "TextEvent.h"
46 #include "TextIterator.h"
47 #include "WheelEvent.h"
48 #include <wtf/text/WTFString.h>
49
50 namespace WebCore {
51
52 TextFieldInputType::TextFieldInputType(HTMLInputElement* element)
53     : InputType(element)
54 {
55 }
56
57 TextFieldInputType::~TextFieldInputType()
58 {
59 }
60
61 bool TextFieldInputType::isTextField() const
62 {
63     return true;
64 }
65
66 bool TextFieldInputType::valueMissing(const String& value) const
67 {
68     return value.isEmpty();
69 }
70
71 bool TextFieldInputType::canSetSuggestedValue()
72 {
73     return true;
74 }
75
76 void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChanged, bool sendChangeEvent)
77 {
78     InputType::setValue(sanitizedValue, valueChanged, sendChangeEvent);
79     element()->updatePlaceholderVisibility(false);
80
81     if (valueChanged)
82         element()->updateInnerTextValue();
83
84     unsigned max = visibleValue().length();
85     if (element()->focused())
86         element()->setSelectionRange(max, max);
87     else
88         element()->cacheSelectionInResponseToSetValue(max);
89 }
90
91 void TextFieldInputType::dispatchChangeEventInResponseToSetValue()
92 {
93     // If the user is still editing this field, dispatch an input event rather than a change event.
94     // The change event will be dispatched when editing finishes.
95     if (element()->focused()) {
96         element()->dispatchFormControlInputEvent();
97         return;
98     }
99     InputType::dispatchChangeEventInResponseToSetValue();
100 }
101
102 void TextFieldInputType::handleKeydownEvent(KeyboardEvent* event)
103 {
104     if (!element()->focused())
105         return;
106     Frame* frame = element()->document()->frame();
107     if (!frame || !frame->editor()->doTextFieldCommandFromEvent(element(), event))
108         return;
109     event->setDefaultHandled();
110 }
111
112 void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent* event)
113 {
114     if (element()->disabled() || element()->readOnly())
115         return;
116     const String& key = event->keyIdentifier();
117     int step = 0;
118     if (key == "Up")
119         step = 1;
120     else if (key == "Down")
121         step = -1;
122     else
123         return;
124     element()->stepUpFromRenderer(step);
125     event->setDefaultHandled();
126 }
127
128 void TextFieldInputType::handleWheelEventForSpinButton(WheelEvent* event)
129 {
130     if (element()->disabled() || element()->readOnly() || !element()->focused())
131         return;
132     int step = 0;
133     if (event->wheelDeltaY() > 0)
134         step = 1;
135     else if (event->wheelDeltaY() < 0)
136         step = -1;
137     else
138         return;
139     element()->stepUpFromRenderer(step);
140     event->setDefaultHandled();
141 }
142
143 void TextFieldInputType::forwardEvent(Event* event)
144 {
145     if (element()->renderer() && (event->isMouseEvent() || event->isDragEvent() || event->isWheelEvent() || event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)) {
146         RenderTextControlSingleLine* renderTextControl = toRenderTextControlSingleLine(element()->renderer());
147         if (event->type() == eventNames().blurEvent) {
148             if (RenderBox* innerTextRenderer = innerTextElement()->renderBox()) {
149                 if (RenderLayer* innerLayer = innerTextRenderer->layer())
150                     innerLayer->scrollToOffset(!renderTextControl->style()->isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0, RenderLayer::ScrollOffsetClamped);
151             }
152
153             renderTextControl->capsLockStateMayHaveChanged();
154         } else if (event->type() == eventNames().focusEvent)
155             renderTextControl->capsLockStateMayHaveChanged();
156
157         element()->forwardEvent(event);
158     }
159 }
160
161 bool TextFieldInputType::shouldSubmitImplicitly(Event* event)
162 {
163     return (event->type() == eventNames().textInputEvent && event->isTextEvent() && static_cast<TextEvent*>(event)->data() == "\n") || InputType::shouldSubmitImplicitly(event);
164 }
165
166 RenderObject* TextFieldInputType::createRenderer(RenderArena* arena, RenderStyle*) const
167 {
168     return new (arena) RenderTextControlSingleLine(element());
169 }
170
171 bool TextFieldInputType::needsContainer() const
172 {
173 #if ENABLE(INPUT_SPEECH)
174     return element()->isSpeechEnabled();
175 #else
176     return false;
177 #endif
178 }
179
180 void TextFieldInputType::createShadowSubtree()
181 {
182     ASSERT(!m_innerText);
183     ASSERT(!m_innerBlock);
184     ASSERT(!m_innerSpinButton);
185
186     Document* document = element()->document();
187     RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
188     bool shouldHaveSpinButton = theme->shouldHaveSpinButton(element());
189     bool createsContainer = shouldHaveSpinButton || needsContainer();
190
191     ExceptionCode ec = 0;
192     m_innerText = TextControlInnerTextElement::create(document);
193     if (!createsContainer) {
194         element()->ensureShadowRoot()->appendChild(m_innerText, ec);
195         return;
196     }
197
198     ShadowRoot* shadowRoot = element()->ensureShadowRoot();
199     m_container = HTMLDivElement::create(document);
200     m_container->setShadowPseudoId("-webkit-textfield-decoration-container");
201     shadowRoot->appendChild(m_container, ec);
202
203     m_innerBlock = TextControlInnerElement::create(document);
204     m_innerBlock->appendChild(m_innerText, ec);
205     m_container->appendChild(m_innerBlock, ec);
206
207 #if ENABLE(INPUT_SPEECH)
208     ASSERT(!m_speechButton);
209     if (element()->isSpeechEnabled()) {
210         m_speechButton = InputFieldSpeechButtonElement::create(document);
211         m_container->appendChild(m_speechButton, ec);
212     }
213 #endif
214
215     if (shouldHaveSpinButton) {
216         m_innerSpinButton = SpinButtonElement::create(document);
217         m_container->appendChild(m_innerSpinButton, ec);
218     }
219 }
220
221 HTMLElement* TextFieldInputType::containerElement() const
222 {
223     return m_container.get();
224 }
225
226 HTMLElement* TextFieldInputType::innerBlockElement() const
227 {
228     return m_innerBlock.get();
229 }
230
231 HTMLElement* TextFieldInputType::innerTextElement() const
232 {
233     ASSERT(m_innerText);
234     return m_innerText.get();
235 }
236
237 HTMLElement* TextFieldInputType::innerSpinButtonElement() const
238 {
239     return m_innerSpinButton.get();
240 }
241
242 #if ENABLE(INPUT_SPEECH)
243 HTMLElement* TextFieldInputType::speechButtonElement() const
244 {
245     return m_speechButton.get();
246 }
247 #endif
248
249 HTMLElement* TextFieldInputType::placeholderElement() const
250 {
251     return m_placeholder.get();
252 }
253
254 void TextFieldInputType::destroyShadowSubtree()
255 {
256     InputType::destroyShadowSubtree();
257     m_innerText.clear();
258     m_placeholder.clear();
259     m_innerBlock.clear();
260 #if ENABLE(INPUT_SPEECH)
261     m_speechButton.clear();
262 #endif
263     m_innerSpinButton.clear();
264     m_container.clear();
265 }
266
267 void TextFieldInputType::disabledAttributeChanged()
268 {
269     if (m_innerSpinButton)
270         m_innerSpinButton->releaseCapture();
271 }
272
273 void TextFieldInputType::readonlyAttributeChanged()
274 {
275     if (m_innerSpinButton)
276         m_innerSpinButton->releaseCapture();
277 }
278
279 bool TextFieldInputType::shouldUseInputMethod() const
280 {
281     return true;
282 }
283
284 static bool isASCIILineBreak(UChar c)
285 {
286     return c == '\r' || c == '\n';
287 }
288
289 static String limitLength(const String& string, int maxLength)
290 {
291     unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
292     for (unsigned i = 0; i < newLength; ++i) {
293         const UChar current = string[i];
294         if (current < ' ' && current != '\t') {
295             newLength = i;
296             break;
297         }
298     }
299     return string.left(newLength);
300 }
301
302 String TextFieldInputType::sanitizeValue(const String& proposedValue)
303 {
304 #if ENABLE(WCSS)
305     if (!element()->isConformToInputMask(proposedValue)) {
306         if (isConformToInputMask(element()->value()))
307             return element->value();
308         return String();
309     }
310 #endif
311     return limitLength(proposedValue.removeCharacters(isASCIILineBreak), HTMLInputElement::maximumLength);
312 }
313
314 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
315 {
316     // Make sure that the text to be inserted will not violate the maxLength.
317
318     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
319     // because they can be mismatched by sanitizeValue() in
320     // HTMLInputElement::subtreeHasChanged() in some cases.
321     unsigned oldLength = numGraphemeClusters(element()->innerTextValue());
322
323     // selectionLength represents the selection length of this text field to be
324     // removed by this insertion.
325     // If the text field has no focus, we don't need to take account of the
326     // selection length. The selection is the source of text drag-and-drop in
327     // that case, and nothing in the text field will be removed.
328     unsigned selectionLength = element()->focused() ? numGraphemeClusters(plainText(element()->document()->frame()->selection()->selection().toNormalizedRange().get())) : 0;
329     ASSERT(oldLength >= selectionLength);
330
331     // Selected characters will be removed by the next text event.
332     unsigned baseLength = oldLength - selectionLength;
333     unsigned maxLength = static_cast<unsigned>(isTextType() ? element()->maxLength() : HTMLInputElement::maximumLength); // maxLength can never be negative.
334     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
335
336     // Truncate the inserted text to avoid violating the maxLength and other constraints.
337 #if ENABLE(WCSS)
338     RefPtr<Range> range = element()->document()->frame()->selection()->selection().toNormalizedRange();
339     String candidateString = toRenderTextControlSingleLine(element()->renderer())->text();
340     if (selectionLength)
341         candidateString.replace(range->startOffset(), range->endOffset(), event->text());
342     else
343         candidateString.insert(event->text(), range->startOffset());
344     if (!element()->isConformToInputMask(candidateString)) {
345         event->setText("");
346         return;
347     }
348 #endif
349
350     String eventText = event->text();
351     eventText.replace("\r\n", " ");
352     eventText.replace('\r', ' ');
353     eventText.replace('\n', ' ');
354
355     event->setText(limitLength(eventText, appendableLength));
356 }
357
358 bool TextFieldInputType::shouldRespectListAttribute()
359 {
360     return true;
361 }
362
363 void TextFieldInputType::updatePlaceholderText()
364 {
365     if (!supportsPlaceholder())
366         return;
367     ExceptionCode ec = 0;
368     String placeholderText = element()->strippedPlaceholder();
369     if (placeholderText.isEmpty()) {
370         if (m_placeholder) {
371             m_placeholder->parentNode()->removeChild(m_placeholder.get(), ec);
372             ASSERT(!ec);
373             m_placeholder.clear();
374         }
375         return;
376     }
377     if (!m_placeholder) {
378         m_placeholder = HTMLDivElement::create(element()->document());
379         m_placeholder->setShadowPseudoId("-webkit-input-placeholder");
380         element()->shadowRoot()->insertBefore(m_placeholder, m_container ? m_container->nextSibling() : innerTextElement()->nextSibling(), ec);
381         ASSERT(!ec);
382     }
383     m_placeholder->setInnerText(placeholderText, ec);
384     ASSERT(!ec);
385 }
386
387 } // namespace WebCore