WebCore/rendering/TextControlInnerElements.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "SpeechInput.h"
       
    43 
       
    44 namespace WebCore {
       
    45 
       
    46 using namespace HTMLNames;
       
    47 
       
    48 class RenderTextControlInnerBlock : public RenderBlock {
       
    49 public:
       
    50     RenderTextControlInnerBlock(Node* node, bool isMultiLine) : RenderBlock(node), m_multiLine(isMultiLine) { }
       
    51 
       
    52 private:
       
    53     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
       
    54     virtual VisiblePosition positionForPoint(const IntPoint&);
       
    55 
       
    56     bool m_multiLine;
       
    57 };
       
    58 
       
    59 bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
       
    60 {
       
    61     RenderObject* renderer = node()->shadowAncestorNode()->renderer();
       
    62 
       
    63     bool placeholderIsVisible = false;
       
    64     if (renderer->isTextField())
       
    65         placeholderIsVisible = toRenderTextControlSingleLine(renderer)->placeholderIsVisible();
       
    66 
       
    67     return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, placeholderIsVisible ? HitTestBlockBackground : hitTestAction);
       
    68 }
       
    69 
       
    70 VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point)
       
    71 {
       
    72     IntPoint contentsPoint(point);
       
    73 
       
    74     // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that
       
    75     // into account here.
       
    76     if (m_multiLine) {
       
    77         RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer());
       
    78         if (renderer->hasOverflowClip())
       
    79             contentsPoint += renderer->layer()->scrolledContentOffset();
       
    80     }
       
    81 
       
    82     return RenderBlock::positionForPoint(contentsPoint);
       
    83 }
       
    84 
       
    85 // ----------------------------
       
    86 
       
    87 TextControlInnerElement::TextControlInnerElement(Document* document, Node* shadowParent)
       
    88     : HTMLDivElement(divTag, document)
       
    89     , m_shadowParent(shadowParent)
       
    90 {
       
    91 }
       
    92 
       
    93 PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(Node* shadowParent)
       
    94 {
       
    95     return adoptRef(new TextControlInnerElement(shadowParent->document(), shadowParent));
       
    96 }
       
    97 
       
    98 void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<RenderStyle> style, RenderArena* arena)
       
    99 {
       
   100     // When adding these elements, create the renderer & style first before adding to the DOM.
       
   101     // Otherwise, the render tree will create some anonymous blocks that will mess up our layout.
       
   102 
       
   103     // Create the renderer with the specified style
       
   104     RenderObject* renderer = createRenderer(arena, style.get());
       
   105     if (renderer) {
       
   106         setRenderer(renderer);
       
   107         renderer->setStyle(style);
       
   108     }
       
   109     
       
   110     // Set these explicitly since this normally happens during an attach()
       
   111     setAttached();
       
   112     setInDocument();
       
   113     
       
   114     // For elements without a shadow parent, add the node to the DOM normally.
       
   115     if (!m_shadowParent)
       
   116         parent->legacyParserAddChild(this);
       
   117     
       
   118     // Add the renderer to the render tree
       
   119     if (renderer)
       
   120         parent->renderer()->addChild(renderer);
       
   121 }
       
   122 
       
   123 // ----------------------------
       
   124 
       
   125 inline TextControlInnerTextElement::TextControlInnerTextElement(Document* document, Node* shadowParent)
       
   126     : TextControlInnerElement(document, shadowParent)
       
   127 {
       
   128 }
       
   129 
       
   130 PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document* document, Node* shadowParent)
       
   131 {
       
   132     return adoptRef(new TextControlInnerTextElement(document, shadowParent));
       
   133 }
       
   134 
       
   135 void TextControlInnerTextElement::defaultEventHandler(Event* event)
       
   136 {
       
   137     // FIXME: In the future, we should add a way to have default event listeners.
       
   138     // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
       
   139     // Or possibly we could just use a normal event listener.
       
   140     if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
       
   141         if (Node* shadowAncestor = shadowAncestorNode())
       
   142             shadowAncestor->defaultEventHandler(event);
       
   143     }
       
   144     if (event->defaultHandled())
       
   145         HTMLDivElement::defaultEventHandler(event);
       
   146 }
       
   147 
       
   148 RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*)
       
   149 {
       
   150     bool multiLine = false;
       
   151     Node* shadowAncestor = shadowAncestorNode();
       
   152     if (shadowAncestor && shadowAncestor->renderer()) {
       
   153         ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea());
       
   154         multiLine = shadowAncestor->renderer()->isTextArea();
       
   155     }
       
   156     return new (arena) RenderTextControlInnerBlock(this, multiLine);
       
   157 }
       
   158 
       
   159 // ----------------------------
       
   160 
       
   161 inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* document)
       
   162     : TextControlInnerElement(document)
       
   163 {
       
   164 }
       
   165 
       
   166 PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document* document)
       
   167 {
       
   168     return adoptRef(new SearchFieldResultsButtonElement(document));
       
   169 }
       
   170 
       
   171 void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
       
   172 {
       
   173     // On mousedown, bring up a menu, if needed
       
   174     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
       
   175     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   176         input->focus();
       
   177         input->select();
       
   178         RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer());
       
   179         if (renderer->popupIsVisible())
       
   180             renderer->hidePopup();
       
   181         else if (input->maxResults() > 0)
       
   182             renderer->showPopup();
       
   183         event->setDefaultHandled();
       
   184     }
       
   185 
       
   186     if (!event->defaultHandled())
       
   187         HTMLDivElement::defaultEventHandler(event);
       
   188 }
       
   189 
       
   190 // ----------------------------
       
   191 
       
   192 inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document)
       
   193     : TextControlInnerElement(document)
       
   194     , m_capturing(false)
       
   195 {
       
   196 }
       
   197 
       
   198 PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document* document)
       
   199 {
       
   200     return adoptRef(new SearchFieldCancelButtonElement(document));
       
   201 }
       
   202 
       
   203 void SearchFieldCancelButtonElement::detach()
       
   204 {
       
   205     if (m_capturing) {
       
   206         if (Frame* frame = document()->frame())
       
   207             frame->eventHandler()->setCapturingMouseEventsNode(0);      
       
   208     }
       
   209     TextControlInnerElement::detach();
       
   210 }
       
   211 
       
   212 
       
   213 void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
       
   214 {
       
   215     // If the element is visible, on mouseup, clear the value, and set selection
       
   216     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
       
   217     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   218         if (renderer() && renderer()->visibleToHitTesting()) {
       
   219             if (Frame* frame = document()->frame()) {
       
   220                 frame->eventHandler()->setCapturingMouseEventsNode(this);
       
   221                 m_capturing = true;
       
   222             }
       
   223         }
       
   224         input->focus();
       
   225         input->select();
       
   226         event->setDefaultHandled();
       
   227     }
       
   228     if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   229         if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
       
   230             if (Frame* frame = document()->frame()) {
       
   231                 frame->eventHandler()->setCapturingMouseEventsNode(0);
       
   232                 m_capturing = false;
       
   233             }
       
   234             if (hovered()) {
       
   235                 input->setValue("");
       
   236                 input->onSearch();
       
   237                 event->setDefaultHandled();
       
   238             }
       
   239         }
       
   240     }
       
   241 
       
   242     if (!event->defaultHandled())
       
   243         HTMLDivElement::defaultEventHandler(event);
       
   244 }
       
   245 
       
   246 // ----------------------------
       
   247 
       
   248 inline SpinButtonElement::SpinButtonElement(Node* shadowParent)
       
   249     : TextControlInnerElement(shadowParent->document(), shadowParent)
       
   250     , m_capturing(false)
       
   251     , m_upDownState(Indeterminate)
       
   252 {
       
   253 }
       
   254 
       
   255 PassRefPtr<SpinButtonElement> SpinButtonElement::create(Node* shadowParent)
       
   256 {
       
   257     return adoptRef(new SpinButtonElement(shadowParent));
       
   258 }
       
   259 
       
   260 void SpinButtonElement::defaultEventHandler(Event* event)
       
   261 {
       
   262     if (!event->isMouseEvent()) {
       
   263         if (!event->defaultHandled())
       
   264             HTMLDivElement::defaultEventHandler(event);
       
   265         return;
       
   266     }
       
   267 
       
   268     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
       
   269     if (mouseEvent->button() != LeftButton) {
       
   270         if (!event->defaultHandled())
       
   271             HTMLDivElement::defaultEventHandler(event);
       
   272         return;
       
   273     }
       
   274 
       
   275     RenderBox* box = renderBox();
       
   276     if (!box) {
       
   277         if (!event->defaultHandled())
       
   278             HTMLDivElement::defaultEventHandler(event);
       
   279         return;        
       
   280     }
       
   281     
       
   282     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
       
   283     if (input->disabled() || input->isReadOnlyFormControl()) {
       
   284         if (!event->defaultHandled())
       
   285             HTMLDivElement::defaultEventHandler(event);
       
   286         return;
       
   287     }
       
   288 
       
   289     IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true));
       
   290     if (event->type() == eventNames().clickEvent) {
       
   291         if (box->borderBoxRect().contains(local)) {
       
   292             RefPtr<Node> protector(input);
       
   293             input->focus();
       
   294             input->select();
       
   295             if (local.y() < box->height() / 2)
       
   296                 input->stepUpFromRenderer(1);
       
   297             else
       
   298                 input->stepUpFromRenderer(-1);
       
   299             event->setDefaultHandled();
       
   300         }
       
   301     } else if (event->type() == eventNames().mousemoveEvent) {
       
   302         if (box->borderBoxRect().contains(local)) {
       
   303             if (!m_capturing) {
       
   304                 if (Frame* frame = document()->frame()) {
       
   305                     frame->eventHandler()->setCapturingMouseEventsNode(input);
       
   306                     m_capturing = true;
       
   307                 }
       
   308             }
       
   309             UpDownState oldUpDownState = m_upDownState;
       
   310             m_upDownState = local.y() < box->height() / 2 ? Up : Down;
       
   311             if (m_upDownState != oldUpDownState)
       
   312                 renderer()->repaint();
       
   313         } else {
       
   314             if (m_capturing) {
       
   315                 if (Frame* frame = document()->frame()) {
       
   316                     frame->eventHandler()->setCapturingMouseEventsNode(0);
       
   317                     m_capturing = false;
       
   318                 }
       
   319             }
       
   320         }
       
   321     }
       
   322 
       
   323     if (!event->defaultHandled())
       
   324         HTMLDivElement::defaultEventHandler(event);
       
   325 }
       
   326 
       
   327 void SpinButtonElement::setHovered(bool flag)
       
   328 {
       
   329     if (!hovered() && flag)
       
   330         m_upDownState = Indeterminate;
       
   331     TextControlInnerElement::setHovered(flag);
       
   332 }
       
   333 
       
   334 
       
   335 // ----------------------------
       
   336 
       
   337 #if ENABLE(INPUT_SPEECH)
       
   338 
       
   339 inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(Document* document)
       
   340     : TextControlInnerElement(document)
       
   341     , m_capturing(false)
       
   342 {
       
   343 }
       
   344 
       
   345 PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(Document* document)
       
   346 {
       
   347     return adoptRef(new InputFieldSpeechButtonElement(document));
       
   348 }
       
   349 
       
   350 void InputFieldSpeechButtonElement::defaultEventHandler(Event* event)
       
   351 {
       
   352     // On mouse down, select the text and set focus.
       
   353     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
       
   354     if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   355         if (renderer() && renderer()->visibleToHitTesting()) {
       
   356             if (Frame* frame = document()->frame()) {
       
   357                 frame->eventHandler()->setCapturingMouseEventsNode(this);
       
   358                 m_capturing = true;
       
   359             }
       
   360         }
       
   361         // The call to focus() below dispatches a focus event, and an event handler in the page might
       
   362         // remove the input element from DOM. To make sure it remains valid until we finish our work
       
   363         // here, we take a temporary reference.
       
   364         RefPtr<HTMLInputElement> holdRef(input);
       
   365         input->focus();
       
   366         input->select();
       
   367         event->setDefaultHandled();
       
   368     }
       
   369     // On mouse up, start speech recognition.
       
   370     if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   371         if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
       
   372             if (Frame* frame = document()->frame()) {
       
   373                 frame->eventHandler()->setCapturingMouseEventsNode(0);
       
   374                 m_capturing = false;
       
   375             }
       
   376             if (hovered()) {
       
   377                 speechInput()->startRecognition();
       
   378                 event->setDefaultHandled();
       
   379             }
       
   380         }
       
   381     }
       
   382 
       
   383     if (!event->defaultHandled())
       
   384         HTMLDivElement::defaultEventHandler(event);
       
   385 }
       
   386 
       
   387 SpeechInput* InputFieldSpeechButtonElement::speechInput()
       
   388 {
       
   389     if (!m_speechInput)
       
   390         m_speechInput.set(new SpeechInput(document()->page()->speechInputClient(), this));
       
   391     return m_speechInput.get();
       
   392 }
       
   393 
       
   394 void InputFieldSpeechButtonElement::recordingComplete()
       
   395 {
       
   396     // FIXME: Add UI feedback here to indicate that audio recording stopped and recognition is
       
   397     // in progress.
       
   398 }
       
   399 
       
   400 void InputFieldSpeechButtonElement::setRecognitionResult(const String& result)
       
   401 {
       
   402     HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
       
   403     // The call to setValue() below dispatches an event, and an event handler in the page might
       
   404     // remove the input element from DOM. To make sure it remains valid until we finish our work
       
   405     // here, we take a temporary reference.
       
   406     RefPtr<HTMLInputElement> holdRef(input);
       
   407     input->setValue(result);
       
   408     input->dispatchFormControlChangeEvent();
       
   409     renderer()->repaint();
       
   410 }
       
   411 
       
   412 void InputFieldSpeechButtonElement::detach()
       
   413 {
       
   414     if (m_capturing) {
       
   415         if (Frame* frame = document()->frame())
       
   416             frame->eventHandler()->setCapturingMouseEventsNode(0);      
       
   417     }
       
   418     TextControlInnerElement::detach();
       
   419 }
       
   420 
       
   421 #endif // ENABLE(INPUT_SPEECH)
       
   422 
       
   423 }