2011-05-23 Sheriff Bot <webkit.review.bot@gmail.com>
[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 "Frame.h"
37 #include "HTMLInputElement.h"
38 #include "KeyboardEvent.h"
39 #include "RenderTextControlSingleLine.h"
40 #include "TextEvent.h"
41 #include "TextIterator.h"
42 #include "WheelEvent.h"
43 #include <wtf/text/WTFString.h>
44
45 namespace WebCore {
46
47 bool TextFieldInputType::isTextField() const
48 {
49     return true;
50 }
51
52 bool TextFieldInputType::valueMissing(const String& value) const
53 {
54     return value.isEmpty();
55 }
56
57 bool TextFieldInputType::canSetSuggestedValue()
58 {
59     return true;
60 }
61
62 void TextFieldInputType::handleKeydownEvent(KeyboardEvent* event)
63 {
64     if (!element()->focused())
65         return;
66     Frame* frame = element()->document()->frame();
67     if (!frame || !frame->editor()->doTextFieldCommandFromEvent(element(), event))
68         return;
69     event->setDefaultHandled();
70 }
71
72 void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent* event)
73 {
74     if (element()->disabled() || element()->readOnly())
75         return;
76     const String& key = event->keyIdentifier();
77     int step = 0;
78     if (key == "Up")
79         step = 1;
80     else if (key == "Down")
81         step = -1;
82     else
83         return;
84     element()->stepUpFromRenderer(step);
85     event->setDefaultHandled();
86 }
87
88 void TextFieldInputType::handleWheelEventForSpinButton(WheelEvent* event)
89 {
90     if (element()->disabled() || element()->readOnly() || !element()->focused())
91         return;
92     int step = 0;
93     if (event->wheelDeltaY() > 0)
94         step = 1;
95     else if (event->wheelDeltaY() < 0)
96         step = -1;
97     else
98         return;
99     element()->stepUpFromRenderer(step);
100     event->setDefaultHandled();
101 }
102
103 void TextFieldInputType::forwardEvent(Event* event)
104 {
105     if (element()->renderer() && (event->isMouseEvent() || event->isDragEvent() || event->isWheelEvent() || event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent))
106         toRenderTextControlSingleLine(element()->renderer())->forwardEvent(event);
107 }
108
109 bool TextFieldInputType::shouldSubmitImplicitly(Event* event)
110 {
111     return (event->type() == eventNames().textInputEvent && event->isTextEvent() && static_cast<TextEvent*>(event)->data() == "\n") || InputType::shouldSubmitImplicitly(event);
112 }
113
114 RenderObject* TextFieldInputType::createRenderer(RenderArena* arena, RenderStyle*) const
115 {
116     return new (arena) RenderTextControlSingleLine(element(), element()->placeholderShouldBeVisible());
117 }
118
119 bool TextFieldInputType::shouldUseInputMethod() const
120 {
121     return true;
122 }
123
124 static String replaceEOLAndLimitLength(const String& proposedValue, int maxLength)
125 {
126     String string = proposedValue;
127     string.replace("\r\n", " ");
128     string.replace('\r', ' ');
129     string.replace('\n', ' ');
130
131     unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
132     for (unsigned i = 0; i < newLength; ++i) {
133         const UChar current = string[i];
134         if (current < ' ' && current != '\t') {
135             newLength = i;
136             break;
137         }
138     }
139     return string.left(newLength);
140 }
141
142 String TextFieldInputType::sanitizeValue(const String& proposedValue)
143 {
144 #if ENABLE(WCSS)
145     if (!element()->isConformToInputMask(proposedValue)) {
146         if (isConformToInputMask(element()->value()))
147             return element->value();
148         return String();
149     }
150 #endif
151     return replaceEOLAndLimitLength(proposedValue, HTMLInputElement::maximumLength);
152 }
153
154 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
155 {
156     // Make sure that the text to be inserted will not violate the maxLength.
157
158     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
159     // because they can be mismatched by sanitizeValue() in
160     // RenderTextControlSingleLine::subtreeHasChanged() in some cases.
161     unsigned oldLength = numGraphemeClusters(toRenderTextControlSingleLine(element()->renderer())->text());
162
163     // selectionLength represents the selection length of this text field to be
164     // removed by this insertion.
165     // If the text field has no focus, we don't need to take account of the
166     // selection length. The selection is the source of text drag-and-drop in
167     // that case, and nothing in the text field will be removed.
168     unsigned selectionLength = element()->focused() ? numGraphemeClusters(plainText(element()->document()->frame()->selection()->selection().toNormalizedRange().get())) : 0;
169     ASSERT(oldLength >= selectionLength);
170
171     // Selected characters will be removed by the next text event.
172     unsigned baseLength = oldLength - selectionLength;
173     unsigned maxLength = static_cast<unsigned>(isTextType() ? element()->maxLength() : HTMLInputElement::maximumLength); // maxLength can never be negative.
174     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
175
176     // Truncate the inserted text to avoid violating the maxLength and other constraints.
177 #if ENABLE(WCSS)
178     RefPtr<Range> range = element()->document()->frame()->selection()->selection().toNormalizedRange();
179     String candidateString = toRenderTextControlSingleLine(element()->renderer())->text();
180     if (selectionLength)
181         candidateString.replace(range->startOffset(), range->endOffset(), event->text());
182     else
183         candidateString.insert(event->text(), range->startOffset());
184     if (!element()->isConformToInputMask(candidateString)) {
185         event->setText("");
186         return;
187     }
188 #endif
189     event->setText(replaceEOLAndLimitLength(event->text(), appendableLength));
190 }
191
192 bool TextFieldInputType::shouldRespectListAttribute()
193 {
194     return true;
195 }
196
197 } // namespace WebCore