2
* Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
3
* Copyright (C) 2010 Google Inc. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
28
#include "TextControlInnerElements.h"
30
#include "BeforeTextInsertedEvent.h"
32
#include "EventHandler.h"
33
#include "EventNames.h"
35
#include "HTMLInputElement.h"
36
#include "HTMLNames.h"
37
#include "HTMLTextAreaElement.h"
38
#include "MouseEvent.h"
40
#include "RenderSearchField.h"
41
#include "RenderView.h"
42
#include "ScriptController.h"
43
#include "SpeechInput.h"
44
#include "SpeechInputEvent.h"
45
#include "StyleInheritedData.h"
46
#include "TextEvent.h"
47
#include "TextEventInputType.h"
51
using namespace HTMLNames;
53
TextControlInnerElement::TextControlInnerElement(Document* document)
54
: HTMLDivElement(divTag, document)
56
setHasCustomCallbacks();
59
PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(Document* document)
61
return adoptRef(new TextControlInnerElement(document));
64
PassRefPtr<RenderStyle> TextControlInnerElement::customStyleForRenderer()
66
RenderTextControlSingleLine* parentRenderer = toRenderTextControlSingleLine(shadowHost()->renderer());
67
return parentRenderer->createInnerBlockStyle(parentRenderer->style());
70
// ---------------------------
72
inline TextControlInnerTextElement::TextControlInnerTextElement(Document* document)
73
: HTMLDivElement(divTag, document)
75
setHasCustomCallbacks();
78
PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document* document)
80
return adoptRef(new TextControlInnerTextElement(document));
83
void TextControlInnerTextElement::defaultEventHandler(Event* event)
85
// FIXME: In the future, we should add a way to have default event listeners.
86
// Then we would add one to the text field's inner div, and we wouldn't need this subclass.
87
// Or possibly we could just use a normal event listener.
88
if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
89
Element* shadowAncestor = shadowHost();
90
// A TextControlInnerTextElement can have no host if its been detached,
91
// but kept alive by an EditCommand. In this case, an undo/redo can
92
// cause events to be sent to the TextControlInnerTextElement. To
93
// prevent an infinite loop, we must check for this case before sending
94
// the event up the chain.
96
shadowAncestor->defaultEventHandler(event);
98
if (!event->defaultHandled())
99
HTMLDivElement::defaultEventHandler(event);
102
RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*)
104
return new (arena) RenderTextControlInnerBlock(this);
107
PassRefPtr<RenderStyle> TextControlInnerTextElement::customStyleForRenderer()
109
RenderTextControl* parentRenderer = toRenderTextControl(shadowHost()->renderer());
110
return parentRenderer->createInnerTextStyle(parentRenderer->style());
113
// ----------------------------
115
inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* document)
116
: HTMLDivElement(divTag, document)
120
PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document* document)
122
return adoptRef(new SearchFieldResultsButtonElement(document));
125
const AtomicString& SearchFieldResultsButtonElement::shadowPseudoId() const
127
DEFINE_STATIC_LOCAL(AtomicString, resultsId, ("-webkit-search-results-button", AtomicString::ConstructFromLiteral));
128
DEFINE_STATIC_LOCAL(AtomicString, resultsDecorationId, ("-webkit-search-results-decoration", AtomicString::ConstructFromLiteral));
129
DEFINE_STATIC_LOCAL(AtomicString, decorationId, ("-webkit-search-decoration", AtomicString::ConstructFromLiteral));
130
Element* host = shadowHost();
133
if (HTMLInputElement* input = host->toInputElement()) {
134
if (input->maxResults() < 0)
136
if (input->maxResults() > 0)
138
return resultsDecorationId;
143
void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
145
// On mousedown, bring up a menu, if needed
146
HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost());
147
if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
150
RenderSearchField* renderer = toRenderSearchField(input->renderer());
151
if (renderer->popupIsVisible())
152
renderer->hidePopup();
153
else if (input->maxResults() > 0)
154
renderer->showPopup();
155
event->setDefaultHandled();
158
if (!event->defaultHandled())
159
HTMLDivElement::defaultEventHandler(event);
162
bool SearchFieldResultsButtonElement::willRespondToMouseClickEvents()
167
// ----------------------------
169
inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document)
170
: HTMLDivElement(divTag, document)
175
PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document* document)
177
return adoptRef(new SearchFieldCancelButtonElement(document));
180
const AtomicString& SearchFieldCancelButtonElement::shadowPseudoId() const
182
DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-search-cancel-button", AtomicString::ConstructFromLiteral));
186
void SearchFieldCancelButtonElement::detach()
189
if (Frame* frame = document()->frame())
190
frame->eventHandler()->setCapturingMouseEventsNode(0);
192
HTMLDivElement::detach();
196
void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
198
// If the element is visible, on mouseup, clear the value, and set selection
199
RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost()));
200
if (input->disabled() || input->readOnly()) {
201
if (!event->defaultHandled())
202
HTMLDivElement::defaultEventHandler(event);
206
if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
207
if (renderer() && renderer()->visibleToHitTesting()) {
208
if (Frame* frame = document()->frame()) {
209
frame->eventHandler()->setCapturingMouseEventsNode(this);
215
event->setDefaultHandled();
217
if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
219
if (Frame* frame = document()->frame()) {
220
frame->eventHandler()->setCapturingMouseEventsNode(0);
224
String oldValue = input->value();
225
input->setValueForUser("");
227
event->setDefaultHandled();
232
if (!event->defaultHandled())
233
HTMLDivElement::defaultEventHandler(event);
236
bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents()
238
const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost());
239
if (!input->disabled() && !input->readOnly())
242
return HTMLDivElement::willRespondToMouseClickEvents();
245
// ----------------------------
247
#if ENABLE(INPUT_SPEECH)
249
inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(Document* document)
250
: HTMLDivElement(divTag, document)
257
InputFieldSpeechButtonElement::~InputFieldSpeechButtonElement()
259
SpeechInput* speech = speechInput();
260
if (speech && m_listenerId) { // Could be null when page is unloading.
262
speech->cancelRecognition(m_listenerId);
263
speech->unregisterListener(m_listenerId);
267
PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(Document* document)
269
return adoptRef(new InputFieldSpeechButtonElement(document));
272
void InputFieldSpeechButtonElement::defaultEventHandler(Event* event)
274
// For privacy reasons, only allow clicks directly coming from the user.
275
if (!ScriptController::processingUserGesture()) {
276
HTMLDivElement::defaultEventHandler(event);
280
// The call to focus() below dispatches a focus event, and an event handler in the page might
281
// remove the input element from DOM. To make sure it remains valid until we finish our work
282
// here, we take a temporary reference.
283
RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost()));
285
if (input->disabled() || input->readOnly()) {
286
if (!event->defaultHandled())
287
HTMLDivElement::defaultEventHandler(event);
291
// On mouse down, select the text and set focus.
292
if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
293
if (renderer() && renderer()->visibleToHitTesting()) {
294
if (Frame* frame = document()->frame()) {
295
frame->eventHandler()->setCapturingMouseEventsNode(this);
299
RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
302
event->setDefaultHandled();
304
// On mouse up, release capture cleanly.
305
if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
306
if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
307
if (Frame* frame = document()->frame()) {
308
frame->eventHandler()->setCapturingMouseEventsNode(0);
314
if (event->type() == eventNames().clickEvent && m_listenerId) {
323
// Nothing to do here, we will continue to wait for results.
326
event->setDefaultHandled();
329
if (!event->defaultHandled())
330
HTMLDivElement::defaultEventHandler(event);
333
bool InputFieldSpeechButtonElement::willRespondToMouseClickEvents()
335
const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost());
336
if (!input->disabled() && !input->readOnly())
339
return HTMLDivElement::willRespondToMouseClickEvents();
342
void InputFieldSpeechButtonElement::setState(SpeechInputState state)
344
if (m_state != state) {
346
shadowHost()->renderer()->repaint();
350
SpeechInput* InputFieldSpeechButtonElement::speechInput()
352
return SpeechInput::from(document()->page());
355
void InputFieldSpeechButtonElement::didCompleteRecording(int)
357
setState(Recognizing);
360
void InputFieldSpeechButtonElement::didCompleteRecognition(int)
365
void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputResultArray& results)
369
// The call to setValue() below dispatches an event, and an event handler in the page might
370
// remove the input element from DOM. To make sure it remains valid until we finish our work
371
// here, we take a temporary reference.
372
RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost()));
373
if (input->disabled() || input->readOnly())
376
RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
377
if (document() && document()->domWindow()) {
378
// Call selectionChanged, causing the element to cache the selection,
379
// so that the text event inserts the text in this element even if
380
// focus has moved away from it.
381
input->selectionChanged(false);
382
input->dispatchEvent(TextEvent::create(document()->domWindow(), results.isEmpty() ? "" : results[0]->utterance(), TextEventInputOther));
385
// This event is sent after the text event so the website can perform actions using the input field content immediately.
386
// It provides alternative recognition hypotheses and notifies that the results come from speech input.
387
input->dispatchEvent(SpeechInputEvent::create(eventNames().webkitspeechchangeEvent, results));
389
// Check before accessing the renderer as the above event could have potentially turned off
390
// speech in the input element, hence removing this button and renderer from the hierarchy.
392
renderer()->repaint();
395
void InputFieldSpeechButtonElement::attach()
397
ASSERT(!m_listenerId);
398
if (SpeechInput* input = SpeechInput::from(document()->page()))
399
m_listenerId = input->registerListener(this);
400
HTMLDivElement::attach();
403
void InputFieldSpeechButtonElement::detach()
406
if (Frame* frame = document()->frame())
407
frame->eventHandler()->setCapturingMouseEventsNode(0);
412
speechInput()->cancelRecognition(m_listenerId);
413
speechInput()->unregisterListener(m_listenerId);
417
HTMLDivElement::detach();
420
void InputFieldSpeechButtonElement::startSpeechInput()
425
RefPtr<HTMLInputElement> input = static_cast<HTMLInputElement*>(shadowHost());
426
AtomicString language = input->computeInheritedLanguage();
427
String grammar = input->getAttribute(webkitgrammarAttr);
428
IntRect rect = document()->view()->contentsToRootView(pixelSnappedBoundingBox());
429
if (speechInput()->startRecognition(m_listenerId, rect, language, grammar, document()->securityOrigin()))
433
void InputFieldSpeechButtonElement::stopSpeechInput()
435
if (m_state == Recording)
436
speechInput()->stopRecording(m_listenerId);
439
const AtomicString& InputFieldSpeechButtonElement::shadowPseudoId() const
441
DEFINE_STATIC_LOCAL(AtomicString, pseudoId, ("-webkit-input-speech-button", AtomicString::ConstructFromLiteral));
445
#endif // ENABLE(INPUT_SPEECH)