Make createRenderer() return RenderElement
[WebKit-https.git] / Source / WebCore / html / shadow / TextControlInnerElements.cpp
1 /*
2  * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Google 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
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "TextControlInnerElements.h"
29
30 #include "Document.h"
31 #include "EventHandler.h"
32 #include "EventNames.h"
33 #include "Frame.h"
34 #include "HTMLInputElement.h"
35 #include "HTMLNames.h"
36 #include "MouseEvent.h"
37 #include "RenderSearchField.h"
38 #include "RenderTextControl.h"
39 #include "RenderView.h"
40 #include "ScriptController.h"
41 #include "SpeechInput.h"
42 #include "SpeechInputEvent.h"
43 #include "TextEvent.h"
44 #include "TextEventInputType.h"
45 #include <wtf/Ref.h>
46
47 namespace WebCore {
48
49 using namespace HTMLNames;
50
51 TextControlInnerContainer::TextControlInnerContainer(Document& document)
52     : HTMLDivElement(divTag, document)
53 {
54 }
55
56 PassRefPtr<TextControlInnerContainer> TextControlInnerContainer::create(Document& document)
57 {
58     return adoptRef(new TextControlInnerContainer(document));
59 }
60     
61 RenderElement* TextControlInnerContainer::createRenderer(RenderArena& arena, RenderStyle&)
62 {
63     return new (arena) RenderTextControlInnerContainer(this);
64 }
65
66 TextControlInnerElement::TextControlInnerElement(Document& document)
67     : HTMLDivElement(divTag, document)
68 {
69     setHasCustomStyleResolveCallbacks();
70 }
71
72 PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(Document& document)
73 {
74     return adoptRef(new TextControlInnerElement(document));
75 }
76
77 PassRefPtr<RenderStyle> TextControlInnerElement::customStyleForRenderer()
78 {
79     RenderTextControlSingleLine* parentRenderer = toRenderTextControlSingleLine(shadowHost()->renderer());
80     return parentRenderer->createInnerBlockStyle(parentRenderer->style());
81 }
82
83 // ---------------------------
84
85 inline TextControlInnerTextElement::TextControlInnerTextElement(Document& document)
86     : HTMLDivElement(divTag, document)
87 {
88     setHasCustomStyleResolveCallbacks();
89 }
90
91 PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document& document)
92 {
93     return adoptRef(new TextControlInnerTextElement(document));
94 }
95
96 void TextControlInnerTextElement::defaultEventHandler(Event* event)
97 {
98     // FIXME: In the future, we should add a way to have default event listeners.
99     // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
100     // Or possibly we could just use a normal event listener.
101     if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
102         Element* shadowAncestor = shadowHost();
103         // A TextControlInnerTextElement can have no host if its been detached,
104         // but kept alive by an EditCommand. In this case, an undo/redo can
105         // cause events to be sent to the TextControlInnerTextElement. To
106         // prevent an infinite loop, we must check for this case before sending
107         // the event up the chain.
108         if (shadowAncestor)
109             shadowAncestor->defaultEventHandler(event);
110     }
111     if (!event->defaultHandled())
112         HTMLDivElement::defaultEventHandler(event);
113 }
114
115 RenderElement* TextControlInnerTextElement::createRenderer(RenderArena& arena, RenderStyle&)
116 {
117     return new (arena) RenderTextControlInnerBlock(this);
118 }
119
120 PassRefPtr<RenderStyle> TextControlInnerTextElement::customStyleForRenderer()
121 {
122     RenderTextControl* parentRenderer = toRenderTextControl(shadowHost()->renderer());
123     return parentRenderer->createInnerTextStyle(parentRenderer->style());
124 }
125
126 // ----------------------------
127
128 inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document& document)
129     : HTMLDivElement(divTag, document)
130 {
131 }
132
133 PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document& document)
134 {
135     return adoptRef(new SearchFieldResultsButtonElement(document));
136 }
137
138 const AtomicString& SearchFieldResultsButtonElement::shadowPseudoId() const
139 {
140     DEFINE_STATIC_LOCAL(AtomicString, resultsId, ("-webkit-search-results-button", AtomicString::ConstructFromLiteral));
141     DEFINE_STATIC_LOCAL(AtomicString, resultsDecorationId, ("-webkit-search-results-decoration", AtomicString::ConstructFromLiteral));
142     DEFINE_STATIC_LOCAL(AtomicString, decorationId, ("-webkit-search-decoration", AtomicString::ConstructFromLiteral));
143     Element* host = shadowHost();
144     if (!host)
145         return resultsId;
146     if (HTMLInputElement* input = host->toInputElement()) {
147         if (input->maxResults() < 0)
148             return decorationId;
149         if (input->maxResults() > 0)
150             return resultsId;
151         return resultsDecorationId;
152     }
153     return resultsId;
154 }
155
156 void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
157 {
158     // On mousedown, bring up a menu, if needed
159     HTMLInputElement* input = toHTMLInputElement(shadowHost());
160     if (input && event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
161         input->focus();
162         input->select();
163         RenderSearchField* renderer = toRenderSearchField(input->renderer());
164         if (renderer->popupIsVisible())
165             renderer->hidePopup();
166         else if (input->maxResults() > 0)
167             renderer->showPopup();
168         event->setDefaultHandled();
169     }
170
171     if (!event->defaultHandled())
172         HTMLDivElement::defaultEventHandler(event);
173 }
174
175 bool SearchFieldResultsButtonElement::willRespondToMouseClickEvents()
176 {
177     return true;
178 }
179
180 // ----------------------------
181
182 inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document& document)
183     : HTMLDivElement(divTag, document)
184     , m_capturing(false)
185 {
186     setHasCustomStyleResolveCallbacks();
187 }
188
189 PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document& document)
190 {
191     return adoptRef(new SearchFieldCancelButtonElement(document));
192 }
193
194 const AtomicString& SearchFieldCancelButtonElement::shadowPseudoId() const
195 {
196     DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-search-cancel-button", AtomicString::ConstructFromLiteral));
197     return pseudoId;
198 }
199
200 void SearchFieldCancelButtonElement::willDetachRenderers()
201 {
202     if (m_capturing) {
203         if (Frame* frame = document().frame())
204             frame->eventHandler().setCapturingMouseEventsNode(0);
205     }
206 }
207
208 void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
209 {
210     // If the element is visible, on mouseup, clear the value, and set selection
211     RefPtr<HTMLInputElement> input(toHTMLInputElement(shadowHost()));
212     if (!input || input->isDisabledOrReadOnly()) {
213         if (!event->defaultHandled())
214             HTMLDivElement::defaultEventHandler(event);
215         return;
216     }
217
218     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
219         if (renderer() && renderer()->visibleToHitTesting()) {
220             if (Frame* frame = document().frame()) {
221                 frame->eventHandler().setCapturingMouseEventsNode(this);
222                 m_capturing = true;
223             }
224         }
225         input->focus();
226         input->select();
227         event->setDefaultHandled();
228     }
229     if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
230         if (m_capturing) {
231             if (Frame* frame = document().frame()) {
232                 frame->eventHandler().setCapturingMouseEventsNode(0);
233                 m_capturing = false;
234             }
235             if (hovered()) {
236                 String oldValue = input->value();
237                 input->setValueForUser("");
238                 input->onSearch();
239                 event->setDefaultHandled();
240             }
241         }
242     }
243
244     if (!event->defaultHandled())
245         HTMLDivElement::defaultEventHandler(event);
246 }
247
248 bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents()
249 {
250     const HTMLInputElement* input = toHTMLInputElement(shadowHost());
251     if (input && !input->isDisabledOrReadOnly())
252         return true;
253
254     return HTMLDivElement::willRespondToMouseClickEvents();
255 }
256
257 // ----------------------------
258
259 #if ENABLE(INPUT_SPEECH)
260
261 inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(Document& document)
262     : HTMLDivElement(divTag, document)
263     , m_capturing(false)
264     , m_state(Idle)
265     , m_listenerId(0)
266 {
267     setHasCustomStyleResolveCallbacks();
268 }
269
270 InputFieldSpeechButtonElement::~InputFieldSpeechButtonElement()
271 {
272     SpeechInput* speech = speechInput();
273     if (speech && m_listenerId)  { // Could be null when page is unloading.
274         if (m_state != Idle)
275             speech->cancelRecognition(m_listenerId);
276         speech->unregisterListener(m_listenerId);
277     }
278 }
279
280 PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(Document& document)
281 {
282     return adoptRef(new InputFieldSpeechButtonElement(document));
283 }
284
285 void InputFieldSpeechButtonElement::defaultEventHandler(Event* event)
286 {
287     // For privacy reasons, only allow clicks directly coming from the user.
288     if (!ScriptController::processingUserGesture()) {
289         HTMLDivElement::defaultEventHandler(event);
290         return;
291     }
292
293     // The call to focus() below dispatches a focus event, and an event handler in the page might
294     // remove the input element from DOM. To make sure it remains valid until we finish our work
295     // here, we take a temporary reference.
296     RefPtr<HTMLInputElement> input(toHTMLInputElement(shadowHost()));
297
298     if (!input || input->isDisabledOrReadOnly()) {
299         if (!event->defaultHandled())
300             HTMLDivElement::defaultEventHandler(event);
301         return;
302     }
303
304     // On mouse down, select the text and set focus.
305     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
306         if (renderer() && renderer()->visibleToHitTesting()) {
307             if (Frame* frame = document().frame()) {
308                 frame->eventHandler().setCapturingMouseEventsNode(this);
309                 m_capturing = true;
310             }
311         }
312         Ref<InputFieldSpeechButtonElement> protect(*this);
313         input->focus();
314         input->select();
315         event->setDefaultHandled();
316     }
317     // On mouse up, release capture cleanly.
318     if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
319         if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
320             if (Frame* frame = document().frame()) {
321                 frame->eventHandler().setCapturingMouseEventsNode(0);
322                 m_capturing = false;
323             }
324         }
325     }
326
327     if (event->type() == eventNames().clickEvent && m_listenerId) {
328         switch (m_state) {
329         case Idle:
330             startSpeechInput();
331             break;
332         case Recording:
333             stopSpeechInput();
334             break;
335         case Recognizing:
336             // Nothing to do here, we will continue to wait for results.
337             break;
338         }
339         event->setDefaultHandled();
340     }
341
342     if (!event->defaultHandled())
343         HTMLDivElement::defaultEventHandler(event);
344 }
345
346 bool InputFieldSpeechButtonElement::willRespondToMouseClickEvents()
347 {
348     const HTMLInputElement* input = toHTMLInputElement(shadowHost());
349     if (input && !input->isDisabledOrReadOnly())
350         return true;
351
352     return HTMLDivElement::willRespondToMouseClickEvents();
353 }
354
355 void InputFieldSpeechButtonElement::setState(SpeechInputState state)
356 {
357     if (m_state != state) {
358         m_state = state;
359         shadowHost()->renderer()->repaint();
360     }
361 }
362
363 SpeechInput* InputFieldSpeechButtonElement::speechInput()
364 {
365     return SpeechInput::from(document().page());
366 }
367
368 void InputFieldSpeechButtonElement::didCompleteRecording(int)
369 {
370     setState(Recognizing);
371 }
372
373 void InputFieldSpeechButtonElement::didCompleteRecognition(int)
374 {
375     setState(Idle);
376 }
377
378 void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputResultArray& results)
379 {
380     m_results = results;
381
382     // The call to setValue() below dispatches an event, and an event handler in the page might
383     // remove the input element from DOM. To make sure it remains valid until we finish our work
384     // here, we take a temporary reference.
385     RefPtr<HTMLInputElement> input(toHTMLInputElement(shadowHost()));
386     if (!input || input->isDisabledOrReadOnly())
387         return;
388
389     Ref<InputFieldSpeechButtonElement> protect(*this);
390     if (document().domWindow()) {
391         // Call selectionChanged, causing the element to cache the selection,
392         // so that the text event inserts the text in this element even if
393         // focus has moved away from it.
394         input->selectionChanged(false);
395         input->dispatchEvent(TextEvent::create(document().domWindow(), results.isEmpty() ? "" : results[0]->utterance(), TextEventInputOther));
396     }
397
398     // This event is sent after the text event so the website can perform actions using the input field content immediately.
399     // It provides alternative recognition hypotheses and notifies that the results come from speech input.
400     input->dispatchEvent(SpeechInputEvent::create(eventNames().webkitspeechchangeEvent, results));
401
402     // Check before accessing the renderer as the above event could have potentially turned off
403     // speech in the input element, hence removing this button and renderer from the hierarchy.
404     if (renderer())
405         renderer()->repaint();
406 }
407
408 void InputFieldSpeechButtonElement::willAttachRenderers()
409 {
410     ASSERT(!m_listenerId);
411     if (SpeechInput* input = SpeechInput::from(document().page()))
412         m_listenerId = input->registerListener(this);
413 }
414
415 void InputFieldSpeechButtonElement::willDetachRenderers()
416 {
417     if (m_capturing) {
418         if (Frame* frame = document().frame())
419             frame->eventHandler().setCapturingMouseEventsNode(0);
420     }
421
422     if (m_listenerId) {
423         if (m_state != Idle)
424             speechInput()->cancelRecognition(m_listenerId);
425         speechInput()->unregisterListener(m_listenerId);
426         m_listenerId = 0;
427     }
428 }
429
430 void InputFieldSpeechButtonElement::startSpeechInput()
431 {
432     if (m_state != Idle)
433         return;
434
435     RefPtr<HTMLInputElement> input = toHTMLInputElement(shadowHost());
436     AtomicString language = input->computeInheritedLanguage();
437     String grammar = input->getAttribute(webkitgrammarAttr);
438     IntRect rect = document().view()->contentsToRootView(pixelSnappedBoundingBox());
439     if (speechInput()->startRecognition(m_listenerId, rect, language, grammar, document().securityOrigin()))
440         setState(Recording);
441 }
442
443 void InputFieldSpeechButtonElement::stopSpeechInput()
444 {
445     if (m_state == Recording)
446         speechInput()->stopRecording(m_listenerId);
447 }
448
449 const AtomicString& InputFieldSpeechButtonElement::shadowPseudoId() const
450 {
451     DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-input-speech-button", AtomicString::ConstructFromLiteral));
452     return pseudoId;
453 }
454
455 #endif // ENABLE(INPUT_SPEECH)
456
457 }