1 /* 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "TextControlInnerElements.h" 28 29 #include "BeforeTextInsertedEvent.h" 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 "HTMLTextAreaElement.h" 37 #include "MouseEvent.h" 38 #include "RenderLayer.h" 39 #include "RenderTextControlSingleLine.h" 40 41 namespace WebCore { 42 43 class RenderTextControlInnerBlock : public RenderBlock { 44 public: 45 RenderTextControlInnerBlock(Node* node, bool isMultiLine) : RenderBlock(node), m_multiLine(isMultiLine) { } 46 47 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction); 48 virtual VisiblePosition positionForPoint(const IntPoint&); 49 private: 50 bool m_multiLine; 51 }; 52 53 bool RenderTextControlInnerBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) 54 { 55 RenderObject* renderer = node()->shadowAncestorNode()->renderer(); 56 57 bool placeholderIsVisible = false; 58 if (renderer->isTextField()) 59 placeholderIsVisible = toRenderTextControlSingleLine(renderer)->placeholderIsVisible(); 60 61 return RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, placeholderIsVisible ? HitTestBlockBackground : hitTestAction); 62 } 63 64 VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point) 65 { 66 int contentsX = point.x(); 67 int contentsY = point.y(); 68 69 // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that 70 // into account here. 71 if (m_multiLine) { 72 RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer()); 73 if (renderer->hasOverflowClip()) 74 renderer->layer()->addScrolledContentOffset(contentsX, contentsY); 75 } 76 77 return RenderBlock::positionForPoint(IntPoint(contentsX, contentsY)); 78 } 79 80 TextControlInnerElement::TextControlInnerElement(Document* doc, Node* shadowParent) 81 : HTMLDivElement(HTMLNames::divTag, doc) 82 , m_shadowParent(shadowParent) 83 { 84 } 85 86 void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<RenderStyle> style, RenderArena* arena) 87 { 88 // When adding these elements, create the renderer & style first before adding to the DOM. 89 // Otherwise, the render tree will create some anonymous blocks that will mess up our layout. 90 91 // Create the renderer with the specified style 92 RenderObject* renderer = createRenderer(arena, style.get()); 93 if (renderer) { 94 setRenderer(renderer); 95 renderer->setStyle(style); 96 } 97 98 // Set these explicitly since this normally happens during an attach() 99 setAttached(); 100 setInDocument(true); 101 102 // For elements without a shadow parent, add the node to the DOM normally. 103 if (!m_shadowParent) 104 parent->addChild(this); 105 106 // Add the renderer to the render tree 107 if (renderer) 108 parent->renderer()->addChild(renderer); 109 } 110 111 TextControlInnerTextElement::TextControlInnerTextElement(Document* doc, Node* shadowParent) 112 : TextControlInnerElement(doc, shadowParent) 113 { 114 } 115 116 void TextControlInnerTextElement::defaultEventHandler(Event* evt) 117 { 118 // FIXME: In the future, we should add a way to have default event listeners. Then we would add one to the text field's inner div, and we wouldn't need this subclass. 119 Node* shadowAncestor = shadowAncestorNode(); 120 if (shadowAncestor && shadowAncestor->renderer()) { 121 ASSERT(shadowAncestor->renderer()->isTextControl()); 122 if (evt->isBeforeTextInsertedEvent()) { 123 if (shadowAncestor->renderer()->isTextField()) 124 static_cast<HTMLInputElement*>(shadowAncestor)->defaultEventHandler(evt); 125 else 126 static_cast<HTMLTextAreaElement*>(shadowAncestor)->defaultEventHandler(evt); 127 } 128 if (evt->type() == eventNames().webkitEditableContentChangedEvent) 129 toRenderTextControl(shadowAncestor->renderer())->subtreeHasChanged(); 130 } 131 if (!evt->defaultHandled()) 132 HTMLDivElement::defaultEventHandler(evt); 133 } 134 135 RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*) 136 { 137 bool multiLine = false; 138 Node* shadowAncestor = shadowAncestorNode(); 139 if (shadowAncestor && shadowAncestor->renderer()) { 140 ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea()); 141 multiLine = shadowAncestor->renderer()->isTextArea(); 142 } 143 return new (arena) RenderTextControlInnerBlock(this, multiLine); 144 } 145 146 SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* doc) 147 : TextControlInnerElement(doc) 148 { 149 } 150 151 void SearchFieldResultsButtonElement::defaultEventHandler(Event* evt) 152 { 153 // On mousedown, bring up a menu, if needed 154 HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); 155 if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 156 input->focus(); 157 input->select(); 158 RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer()); 159 if (renderer->popupIsVisible()) 160 renderer->hidePopup(); 161 else if (input->maxResults() > 0) 162 renderer->showPopup(); 163 evt->setDefaultHandled(); 164 } 165 if (!evt->defaultHandled()) 166 HTMLDivElement::defaultEventHandler(evt); 167 } 168 169 SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* doc) 170 : TextControlInnerElement(doc) 171 , m_capturing(false) 172 { 173 } 174 175 void SearchFieldCancelButtonElement::detach() 176 { 177 if (m_capturing) { 178 if (Frame* frame = document()->frame()) 179 frame->eventHandler()->setCapturingMouseEventsNode(0); 180 } 181 TextControlInnerElement::detach(); 182 } 183 184 185 void SearchFieldCancelButtonElement::defaultEventHandler(Event* evt) 186 { 187 // If the element is visible, on mouseup, clear the value, and set selection 188 HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); 189 if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 190 input->focus(); 191 input->select(); 192 evt->setDefaultHandled(); 193 if (renderer() && renderer()->visibleToHitTesting()) 194 if (Frame* frame = document()->frame()) { 195 frame->eventHandler()->setCapturingMouseEventsNode(this); 196 m_capturing = true; 197 } 198 } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 199 if (m_capturing && renderer() && renderer()->visibleToHitTesting()) { 200 if (hovered()) { 201 input->setValue(""); 202 input->onSearch(); 203 evt->setDefaultHandled(); 204 } 205 if (Frame* frame = document()->frame()) { 206 frame->eventHandler()->setCapturingMouseEventsNode(0); 207 m_capturing = false; 208 } 209 } 210 } 211 if (!evt->defaultHandled()) 212 HTMLDivElement::defaultEventHandler(evt); 213 } 214 215 } 216