• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "BeforeTextInsertedEvent.h"
31 #include "Document.h"
32 #include "EventHandler.h"
33 #include "EventNames.h"
34 #include "Frame.h"
35 #include "HTMLInputElement.h"
36 #include "HTMLNames.h"
37 #include "HTMLTextAreaElement.h"
38 #include "MouseEvent.h"
39 #include "Page.h"
40 #include "RenderLayer.h"
41 #include "RenderTextControlSingleLine.h"
42 #include "ScrollbarTheme.h"
43 #include "SpeechInput.h"
44 #include "SpeechInputEvent.h"
45 
46 namespace WebCore {
47 
48 using namespace HTMLNames;
49 
TextControlInnerElement(Document * document,HTMLElement * shadowParent)50 TextControlInnerElement::TextControlInnerElement(Document* document, HTMLElement* shadowParent)
51     : HTMLDivElement(divTag, document)
52 {
53     setShadowHost(shadowParent);
54 }
55 
create(HTMLElement * shadowParent)56 PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(HTMLElement* shadowParent)
57 {
58     return adoptRef(new TextControlInnerElement(shadowParent->document(), shadowParent));
59 }
60 
attachInnerElement(Node * parent,PassRefPtr<RenderStyle> style,RenderArena * arena)61 void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<RenderStyle> style, RenderArena* arena)
62 {
63     // When adding these elements, create the renderer & style first before adding to the DOM.
64     // Otherwise, the render tree will create some anonymous blocks that will mess up our layout.
65 
66     // Create the renderer with the specified style
67     RenderObject* renderer = createRenderer(arena, style.get());
68     if (renderer) {
69         setRenderer(renderer);
70         renderer->setStyle(style);
71     }
72 
73     // Set these explicitly since this normally happens during an attach()
74     setAttached();
75     setInDocument();
76 
77     // For elements not yet in shadow DOM, add the node to the DOM normally.
78     if (!isShadowRoot()) {
79         // FIXME: This code seems very wrong.  Why are we magically adding |this| to the DOM here?
80         //        We shouldn't be calling parser API methods outside of the parser!
81         parent->deprecatedParserAddChild(this);
82     }
83 
84     // Add the renderer to the render tree
85     if (renderer)
86         parent->renderer()->addChild(renderer);
87 }
88 
detach()89 void TextControlInnerElement::detach()
90 {
91     HTMLDivElement::detach();
92     // FIXME: Remove once shadow DOM uses Element::setShadowRoot().
93     if (shadowHost())
94         setShadowHost(0);
95 }
96 
97 // ----------------------------
98 
TextControlInnerTextElement(Document * document,HTMLElement * shadowParent)99 inline TextControlInnerTextElement::TextControlInnerTextElement(Document* document, HTMLElement* shadowParent)
100     : TextControlInnerElement(document, shadowParent)
101 {
102 }
103 
create(Document * document,HTMLElement * shadowParent)104 PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document* document, HTMLElement* shadowParent)
105 {
106     return adoptRef(new TextControlInnerTextElement(document, shadowParent));
107 }
108 
defaultEventHandler(Event * event)109 void TextControlInnerTextElement::defaultEventHandler(Event* event)
110 {
111     // FIXME: In the future, we should add a way to have default event listeners.
112     // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
113     // Or possibly we could just use a normal event listener.
114     if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
115         Node* shadowAncestor = shadowAncestorNode();
116         // A TextControlInnerTextElement can be its own shadow ancestor if its been detached, but kept alive by an EditCommand.
117         // In this case, an undo/redo can cause events to be sent to the TextControlInnerTextElement.
118         // To prevent an infinite loop, we must check for this case before sending the event up the chain.
119         if (shadowAncestor && shadowAncestor != this)
120             shadowAncestor->defaultEventHandler(event);
121     }
122     if (!event->defaultHandled())
123         HTMLDivElement::defaultEventHandler(event);
124 }
125 
createRenderer(RenderArena * arena,RenderStyle *)126 RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*)
127 {
128     bool multiLine = false;
129     Node* shadowAncestor = shadowAncestorNode();
130     if (shadowAncestor && shadowAncestor->renderer()) {
131         ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea());
132         multiLine = shadowAncestor->renderer()->isTextArea();
133     }
134     return new (arena) RenderTextControlInnerBlock(this, multiLine);
135 }
136 
137 // ----------------------------
138 
SearchFieldResultsButtonElement(Document * document)139 inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* document)
140     : TextControlInnerElement(document)
141 {
142 }
143 
create(Document * document)144 PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document* document)
145 {
146     return adoptRef(new SearchFieldResultsButtonElement(document));
147 }
148 
defaultEventHandler(Event * event)149 void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
150 {
151     // On mousedown, bring up a menu, if needed
152     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
153     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
154         input->focus();
155         input->select();
156         RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer());
157         if (renderer->popupIsVisible())
158             renderer->hidePopup();
159         else if (input->maxResults() > 0)
160             renderer->showPopup();
161         event->setDefaultHandled();
162     }
163 
164     if (!event->defaultHandled())
165         HTMLDivElement::defaultEventHandler(event);
166 }
167 
168 // ----------------------------
169 
SearchFieldCancelButtonElement(Document * document)170 inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document)
171     : TextControlInnerElement(document)
172     , m_capturing(false)
173 {
174 }
175 
create(Document * document)176 PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document* document)
177 {
178     return adoptRef(new SearchFieldCancelButtonElement(document));
179 }
180 
detach()181 void SearchFieldCancelButtonElement::detach()
182 {
183     if (m_capturing) {
184         if (Frame* frame = document()->frame())
185             frame->eventHandler()->setCapturingMouseEventsNode(0);
186     }
187     TextControlInnerElement::detach();
188 }
189 
190 
defaultEventHandler(Event * event)191 void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
192 {
193     // If the element is visible, on mouseup, clear the value, and set selection
194     RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
195     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
196         if (renderer() && renderer()->visibleToHitTesting()) {
197             if (Frame* frame = document()->frame()) {
198                 frame->eventHandler()->setCapturingMouseEventsNode(this);
199                 m_capturing = true;
200             }
201         }
202         input->focus();
203         input->select();
204         event->setDefaultHandled();
205     }
206     if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
207         if (m_capturing) {
208             if (Frame* frame = document()->frame()) {
209                 frame->eventHandler()->setCapturingMouseEventsNode(0);
210                 m_capturing = false;
211             }
212             if (hovered()) {
213                 String oldValue = input->value();
214                 input->setValueForUser("");
215                 input->onSearch();
216                 event->setDefaultHandled();
217             }
218         }
219     }
220 
221     if (!event->defaultHandled())
222         HTMLDivElement::defaultEventHandler(event);
223 }
224 
225 // ----------------------------
226 
SpinButtonElement(HTMLElement * shadowParent)227 inline SpinButtonElement::SpinButtonElement(HTMLElement* shadowParent)
228     : TextControlInnerElement(shadowParent->document(), shadowParent)
229     , m_capturing(false)
230     , m_upDownState(Indeterminate)
231     , m_pressStartingState(Indeterminate)
232     , m_repeatingTimer(this, &SpinButtonElement::repeatingTimerFired)
233 {
234 }
235 
create(HTMLElement * shadowParent)236 PassRefPtr<SpinButtonElement> SpinButtonElement::create(HTMLElement* shadowParent)
237 {
238     return adoptRef(new SpinButtonElement(shadowParent));
239 }
240 
detach()241 void SpinButtonElement::detach()
242 {
243     stopRepeatingTimer();
244     if (m_capturing) {
245         if (Frame* frame = document()->frame()) {
246             frame->eventHandler()->setCapturingMouseEventsNode(0);
247             m_capturing = false;
248         }
249     }
250     TextControlInnerElement::detach();
251 }
252 
defaultEventHandler(Event * event)253 void SpinButtonElement::defaultEventHandler(Event* event)
254 {
255     if (!event->isMouseEvent()) {
256         if (!event->defaultHandled())
257             HTMLDivElement::defaultEventHandler(event);
258         return;
259     }
260 
261     RenderBox* box = renderBox();
262     if (!box) {
263         if (!event->defaultHandled())
264             HTMLDivElement::defaultEventHandler(event);
265         return;
266     }
267 
268     RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
269     if (input->disabled() || input->isReadOnlyFormControl()) {
270         if (!event->defaultHandled())
271             HTMLDivElement::defaultEventHandler(event);
272         return;
273     }
274 
275     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
276     IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true));
277     if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) {
278         if (box->borderBoxRect().contains(local)) {
279             // The following functions of HTMLInputElement may run JavaScript
280             // code which detaches this shadow node. We need to take a reference
281             // and check renderer() after such function calls.
282             RefPtr<Node> protector(this);
283             input->focus();
284             input->select();
285             if (renderer()) {
286                 input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1);
287                 if (renderer())
288                     startRepeatingTimer();
289             }
290             event->setDefaultHandled();
291         }
292     } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton)
293         stopRepeatingTimer();
294     else if (event->type() == eventNames().mousemoveEvent) {
295         if (box->borderBoxRect().contains(local)) {
296             if (!m_capturing) {
297                 if (Frame* frame = document()->frame()) {
298                     frame->eventHandler()->setCapturingMouseEventsNode(this);
299                     m_capturing = true;
300                 }
301             }
302             UpDownState oldUpDownState = m_upDownState;
303             m_upDownState = local.y() < box->height() / 2 ? Up : Down;
304             if (m_upDownState != oldUpDownState)
305                 renderer()->repaint();
306         } else {
307             if (m_capturing) {
308                 stopRepeatingTimer();
309                 if (Frame* frame = document()->frame()) {
310                     frame->eventHandler()->setCapturingMouseEventsNode(0);
311                     m_capturing = false;
312                 }
313             }
314         }
315     }
316 
317     if (!event->defaultHandled())
318         HTMLDivElement::defaultEventHandler(event);
319 }
320 
startRepeatingTimer()321 void SpinButtonElement::startRepeatingTimer()
322 {
323     m_pressStartingState = m_upDownState;
324     ScrollbarTheme* theme = ScrollbarTheme::nativeTheme();
325     m_repeatingTimer.start(theme->initialAutoscrollTimerDelay(), theme->autoscrollTimerDelay());
326 }
327 
stopRepeatingTimer()328 void SpinButtonElement::stopRepeatingTimer()
329 {
330     m_repeatingTimer.stop();
331 }
332 
repeatingTimerFired(Timer<SpinButtonElement> *)333 void SpinButtonElement::repeatingTimerFired(Timer<SpinButtonElement>*)
334 {
335     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
336     if (input->disabled() || input->isReadOnlyFormControl())
337         return;
338     // On Mac OS, NSStepper updates the value for the button under the mouse
339     // cursor regardless of the button pressed at the beginning. So the
340     // following check is not needed for Mac OS.
341 #if !OS(MAC_OS_X)
342     if (m_upDownState != m_pressStartingState)
343         return;
344 #endif
345     input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1);
346 }
347 
setHovered(bool flag)348 void SpinButtonElement::setHovered(bool flag)
349 {
350     if (!hovered() && flag)
351         m_upDownState = Indeterminate;
352     TextControlInnerElement::setHovered(flag);
353 }
354 
355 
356 // ----------------------------
357 
358 #if ENABLE(INPUT_SPEECH)
359 
InputFieldSpeechButtonElement(HTMLElement * shadowParent)360 inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(HTMLElement* shadowParent)
361     : TextControlInnerElement(shadowParent->document(), shadowParent)
362     , m_capturing(false)
363     , m_state(Idle)
364     , m_listenerId(document()->page()->speechInput()->registerListener(this))
365 {
366 }
367 
~InputFieldSpeechButtonElement()368 InputFieldSpeechButtonElement::~InputFieldSpeechButtonElement()
369 {
370     SpeechInput* speech = speechInput();
371     if (speech && m_listenerId)  { // Could be null when page is unloading.
372         if (m_state != Idle)
373             speech->cancelRecognition(m_listenerId);
374         speech->unregisterListener(m_listenerId);
375     }
376 }
377 
create(HTMLElement * shadowParent)378 PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(HTMLElement* shadowParent)
379 {
380     return adoptRef(new InputFieldSpeechButtonElement(shadowParent));
381 }
382 
defaultEventHandler(Event * event)383 void InputFieldSpeechButtonElement::defaultEventHandler(Event* event)
384 {
385     // For privacy reasons, only allow clicks directly coming from the user.
386     if (!event->fromUserGesture()) {
387         HTMLDivElement::defaultEventHandler(event);
388         return;
389     }
390 
391     // The call to focus() below dispatches a focus event, and an event handler in the page might
392     // remove the input element from DOM. To make sure it remains valid until we finish our work
393     // here, we take a temporary reference.
394     RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
395 
396     if (input->disabled() || input->isReadOnlyFormControl()) {
397         if (!event->defaultHandled())
398             HTMLDivElement::defaultEventHandler(event);
399         return;
400     }
401 
402     // On mouse down, select the text and set focus.
403     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
404         if (renderer() && renderer()->visibleToHitTesting()) {
405             if (Frame* frame = document()->frame()) {
406                 frame->eventHandler()->setCapturingMouseEventsNode(this);
407                 m_capturing = true;
408             }
409         }
410         RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
411         input->focus();
412         input->select();
413         event->setDefaultHandled();
414     }
415     // On mouse up, release capture cleanly.
416     if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
417         if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
418             if (Frame* frame = document()->frame()) {
419                 frame->eventHandler()->setCapturingMouseEventsNode(0);
420                 m_capturing = false;
421             }
422         }
423     }
424 
425     if (event->type() == eventNames().clickEvent) {
426         switch (m_state) {
427         case Idle: {
428               AtomicString language = input->computeInheritedLanguage();
429               String grammar = input->getAttribute(webkitgrammarAttr);
430               IntRect rect = input->renderer()->absoluteBoundingBoxRect();
431               if (speechInput()->startRecognition(m_listenerId, rect, language, grammar, document()->securityOrigin()))
432                   setState(Recording);
433             }
434             break;
435         case Recording:
436             speechInput()->stopRecording(m_listenerId);
437             break;
438         case Recognizing:
439             // Nothing to do here, we will continue to wait for results.
440             break;
441         }
442         event->setDefaultHandled();
443     }
444 
445     if (!event->defaultHandled())
446         HTMLDivElement::defaultEventHandler(event);
447 }
448 
setState(SpeechInputState state)449 void InputFieldSpeechButtonElement::setState(SpeechInputState state)
450 {
451     if (m_state != state) {
452         m_state = state;
453         shadowAncestorNode()->renderer()->repaint();
454     }
455 }
456 
speechInput()457 SpeechInput* InputFieldSpeechButtonElement::speechInput()
458 {
459     return document()->page() ? document()->page()->speechInput() : 0;
460 }
461 
didCompleteRecording(int)462 void InputFieldSpeechButtonElement::didCompleteRecording(int)
463 {
464     setState(Recognizing);
465 }
466 
didCompleteRecognition(int)467 void InputFieldSpeechButtonElement::didCompleteRecognition(int)
468 {
469     setState(Idle);
470 }
471 
setRecognitionResult(int,const SpeechInputResultArray & results)472 void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputResultArray& results)
473 {
474     m_results = results;
475 
476     // The call to setValue() below dispatches an event, and an event handler in the page might
477     // remove the input element from DOM. To make sure it remains valid until we finish our work
478     // here, we take a temporary reference.
479     RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
480     if (input->disabled() || input->isReadOnlyFormControl())
481         return;
482 
483     RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
484     input->setValue(results.isEmpty() ? "" : results[0]->utterance());
485     input->dispatchEvent(SpeechInputEvent::create(eventNames().webkitspeechchangeEvent, results));
486 
487     // Check before accessing the renderer as the above event could have potentially turned off
488     // speech in the input element, hence removing this button and renderer from the hierarchy.
489     if (renderer())
490         renderer()->repaint();
491 }
492 
detach()493 void InputFieldSpeechButtonElement::detach()
494 {
495     if (m_capturing) {
496         if (Frame* frame = document()->frame())
497             frame->eventHandler()->setCapturingMouseEventsNode(0);
498     }
499 
500     if (m_listenerId) {
501         if (m_state != Idle)
502             speechInput()->cancelRecognition(m_listenerId);
503         speechInput()->unregisterListener(m_listenerId);
504         m_listenerId = 0;
505     }
506 
507     TextControlInnerElement::detach();
508 }
509 
510 #endif // ENABLE(INPUT_SPEECH)
511 
512 }
513