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 "core/html/shadow/TextControlInnerElements.h"
29
30#include "core/HTMLNames.h"
31#include "core/dom/Document.h"
32#include "core/dom/NodeRenderStyle.h"
33#include "core/events/MouseEvent.h"
34#include "core/events/TextEvent.h"
35#include "core/events/TextEventInputType.h"
36#include "core/frame/LocalFrame.h"
37#include "core/html/HTMLInputElement.h"
38#include "core/html/shadow/ShadowElementNames.h"
39#include "core/page/EventHandler.h"
40#include "core/rendering/RenderTextControlSingleLine.h"
41#include "core/rendering/RenderView.h"
42#include "platform/UserGestureIndicator.h"
43
44namespace blink {
45
46using namespace HTMLNames;
47
48TextControlInnerContainer::TextControlInnerContainer(Document& document)
49    : HTMLDivElement(document)
50{
51}
52
53PassRefPtrWillBeRawPtr<TextControlInnerContainer> TextControlInnerContainer::create(Document& document)
54{
55    RefPtrWillBeRawPtr<TextControlInnerContainer> element = adoptRefWillBeNoop(new TextControlInnerContainer(document));
56    element->setAttribute(idAttr, ShadowElementNames::textFieldContainer());
57    return element.release();
58}
59
60RenderObject* TextControlInnerContainer::createRenderer(RenderStyle*)
61{
62    return new RenderTextControlInnerContainer(this);
63}
64
65// ---------------------------
66
67EditingViewPortElement::EditingViewPortElement(Document& document)
68    : HTMLDivElement(document)
69{
70    setHasCustomStyleCallbacks();
71}
72
73PassRefPtrWillBeRawPtr<EditingViewPortElement> EditingViewPortElement::create(Document& document)
74{
75    RefPtrWillBeRawPtr<EditingViewPortElement> element = adoptRefWillBeNoop(new EditingViewPortElement(document));
76    element->setAttribute(idAttr, ShadowElementNames::editingViewPort());
77    return element.release();
78}
79
80PassRefPtr<RenderStyle> EditingViewPortElement::customStyleForRenderer()
81{
82    // FXIME: Move these styles to html.css.
83
84    RefPtr<RenderStyle> style = RenderStyle::create();
85    style->inheritFrom(shadowHost()->renderStyle());
86
87    style->setFlexGrow(1);
88    style->setDisplay(BLOCK);
89    style->setDirection(LTR);
90
91    // We don't want the shadow dom to be editable, so we set this block to
92    // read-only in case the input itself is editable.
93    style->setUserModify(READ_ONLY);
94    style->setUnique();
95
96    return style.release();
97}
98
99// ---------------------------
100
101inline TextControlInnerEditorElement::TextControlInnerEditorElement(Document& document)
102    : HTMLDivElement(document)
103{
104    setHasCustomStyleCallbacks();
105}
106
107PassRefPtrWillBeRawPtr<TextControlInnerEditorElement> TextControlInnerEditorElement::create(Document& document)
108{
109    RefPtrWillBeRawPtr<TextControlInnerEditorElement> element = adoptRefWillBeNoop(new TextControlInnerEditorElement(document));
110    element->setAttribute(idAttr, ShadowElementNames::innerEditor());
111    return element.release();
112}
113
114void TextControlInnerEditorElement::defaultEventHandler(Event* event)
115{
116    // FIXME: In the future, we should add a way to have default event listeners.
117    // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
118    // Or possibly we could just use a normal event listener.
119    if (event->isBeforeTextInsertedEvent() || event->type() == EventTypeNames::webkitEditableContentChanged) {
120        Element* shadowAncestor = shadowHost();
121        // A TextControlInnerTextElement can have no host if its been detached,
122        // but kept alive by an EditCommand. In this case, an undo/redo can
123        // cause events to be sent to the TextControlInnerTextElement. To
124        // prevent an infinite loop, we must check for this case before sending
125        // the event up the chain.
126        if (shadowAncestor)
127            shadowAncestor->defaultEventHandler(event);
128    }
129    if (!event->defaultHandled())
130        HTMLDivElement::defaultEventHandler(event);
131}
132
133RenderObject* TextControlInnerEditorElement::createRenderer(RenderStyle*)
134{
135    return new RenderTextControlInnerBlock(this);
136}
137
138PassRefPtr<RenderStyle> TextControlInnerEditorElement::customStyleForRenderer()
139{
140    RenderObject* parentRenderer = shadowHost()->renderer();
141    if (!parentRenderer || !parentRenderer->isTextControl())
142        return originalStyleForRenderer();
143    RenderTextControl* textControlRenderer = toRenderTextControl(parentRenderer);
144    return textControlRenderer->createInnerEditorStyle(textControlRenderer->style());
145}
146
147// ----------------------------
148
149inline SearchFieldDecorationElement::SearchFieldDecorationElement(Document& document)
150    : HTMLDivElement(document)
151{
152}
153
154PassRefPtrWillBeRawPtr<SearchFieldDecorationElement> SearchFieldDecorationElement::create(Document& document)
155{
156    RefPtrWillBeRawPtr<SearchFieldDecorationElement> element = adoptRefWillBeNoop(new SearchFieldDecorationElement(document));
157    element->setAttribute(idAttr, ShadowElementNames::searchDecoration());
158    return element.release();
159}
160
161const AtomicString& SearchFieldDecorationElement::shadowPseudoId() const
162{
163    DEFINE_STATIC_LOCAL(AtomicString, resultsDecorationId, ("-webkit-search-results-decoration", AtomicString::ConstructFromLiteral));
164    DEFINE_STATIC_LOCAL(AtomicString, decorationId, ("-webkit-search-decoration", AtomicString::ConstructFromLiteral));
165    Element* host = shadowHost();
166    if (!host)
167        return resultsDecorationId;
168    if (isHTMLInputElement(*host)) {
169        if (toHTMLInputElement(host)->maxResults() < 0)
170            return decorationId;
171        return resultsDecorationId;
172    }
173    return resultsDecorationId;
174}
175
176void SearchFieldDecorationElement::defaultEventHandler(Event* event)
177{
178    // On mousedown, focus the search field
179    HTMLInputElement* input = toHTMLInputElement(shadowHost());
180    if (input && event->type() == EventTypeNames::mousedown && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton) {
181        input->focus();
182        input->select();
183        event->setDefaultHandled();
184    }
185
186    if (!event->defaultHandled())
187        HTMLDivElement::defaultEventHandler(event);
188}
189
190bool SearchFieldDecorationElement::willRespondToMouseClickEvents()
191{
192    return true;
193}
194
195// ----------------------------
196
197inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document& document)
198    : HTMLDivElement(document)
199    , m_capturing(false)
200{
201}
202
203PassRefPtrWillBeRawPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document& document)
204{
205    RefPtrWillBeRawPtr<SearchFieldCancelButtonElement> element = adoptRefWillBeNoop(new SearchFieldCancelButtonElement(document));
206    element->setShadowPseudoId(AtomicString("-webkit-search-cancel-button", AtomicString::ConstructFromLiteral));
207    element->setAttribute(idAttr, ShadowElementNames::clearButton());
208    return element.release();
209}
210
211void SearchFieldCancelButtonElement::detach(const AttachContext& context)
212{
213    if (m_capturing) {
214        if (LocalFrame* frame = document().frame())
215            frame->eventHandler().setCapturingMouseEventsNode(nullptr);
216    }
217    HTMLDivElement::detach(context);
218}
219
220
221void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
222{
223    // If the element is visible, on mouseup, clear the value, and set selection
224    RefPtrWillBeRawPtr<HTMLInputElement> input(toHTMLInputElement(shadowHost()));
225    if (!input || input->isDisabledOrReadOnly()) {
226        if (!event->defaultHandled())
227            HTMLDivElement::defaultEventHandler(event);
228        return;
229    }
230
231
232    if (event->type() == EventTypeNames::click && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton) {
233        input->setValueForUser("");
234        input->setAutofilled(false);
235        input->onSearch();
236        event->setDefaultHandled();
237    }
238
239    if (!event->defaultHandled())
240        HTMLDivElement::defaultEventHandler(event);
241}
242
243bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents()
244{
245    const HTMLInputElement* input = toHTMLInputElement(shadowHost());
246    if (input && !input->isDisabledOrReadOnly())
247        return true;
248
249    return HTMLDivElement::willRespondToMouseClickEvents();
250}
251
252}
253