Text control shadow element style shouldn't depend on renderers
[WebKit-https.git] / Source / WebCore / html / shadow / TextControlInnerElements.cpp
1 /*
2  * Copyright (C) 2006, 2008, 2010, 2014 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 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 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 "Document.h"
31 #include "EventNames.h"
32 #include "Frame.h"
33 #include "HTMLInputElement.h"
34 #include "HTMLNames.h"
35 #include "LocalizedStrings.h"
36 #include "MouseEvent.h"
37 #include "PlatformMouseEvent.h"
38 #include "RenderSearchField.h"
39 #include "RenderTextControl.h"
40 #include "RenderView.h"
41 #include "ScriptController.h"
42 #include "TextEvent.h"
43 #include "TextEventInputType.h"
44 #include <wtf/Ref.h>
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 TextControlInnerContainer::TextControlInnerContainer(Document& document)
51     : HTMLDivElement(divTag, document)
52 {
53 }
54
55 Ref<TextControlInnerContainer> TextControlInnerContainer::create(Document& document)
56 {
57     return adoptRef(*new TextControlInnerContainer(document));
58 }
59     
60 RenderPtr<RenderElement> TextControlInnerContainer::createElementRenderer(Ref<RenderStyle>&& style, const RenderTreePosition&)
61 {
62     return createRenderer<RenderTextControlInnerContainer>(*this, WTFMove(style));
63 }
64
65 TextControlInnerElement::TextControlInnerElement(Document& document)
66     : HTMLDivElement(divTag, document)
67 {
68     setHasCustomStyleResolveCallbacks();
69 }
70
71 Ref<TextControlInnerElement> TextControlInnerElement::create(Document& document)
72 {
73     return adoptRef(*new TextControlInnerElement(document));
74 }
75
76 RefPtr<RenderStyle> TextControlInnerElement::customStyleForRenderer(RenderStyle&, RenderStyle* shadowHostStyle)
77 {
78     auto innerContainerStyle = RenderStyle::create();
79     innerContainerStyle.get().inheritFrom(shadowHostStyle);
80
81     innerContainerStyle.get().setFlexGrow(1);
82     // min-width: 0; is needed for correct shrinking.
83     innerContainerStyle.get().setMinWidth(Length(0, Fixed));
84     innerContainerStyle.get().setDisplay(BLOCK);
85     innerContainerStyle.get().setDirection(LTR);
86
87     // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable.
88     innerContainerStyle.get().setUserModify(READ_ONLY);
89
90     return WTFMove(innerContainerStyle);
91 }
92
93 // ---------------------------
94
95 inline TextControlInnerTextElement::TextControlInnerTextElement(Document& document)
96     : HTMLDivElement(divTag, document)
97 {
98     setHasCustomStyleResolveCallbacks();
99 }
100
101 Ref<TextControlInnerTextElement> TextControlInnerTextElement::create(Document& document)
102 {
103     return adoptRef(*new TextControlInnerTextElement(document));
104 }
105
106 void TextControlInnerTextElement::defaultEventHandler(Event* event)
107 {
108     // FIXME: In the future, we should add a way to have default event listeners.
109     // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
110     // Or possibly we could just use a normal event listener.
111     if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
112         Element* shadowAncestor = shadowHost();
113         // A TextControlInnerTextElement can have no host if its been detached,
114         // but kept alive by an EditCommand. In this case, an undo/redo can
115         // cause events to be sent to the TextControlInnerTextElement. To
116         // prevent an infinite loop, we must check for this case before sending
117         // the event up the chain.
118         if (shadowAncestor)
119             shadowAncestor->defaultEventHandler(event);
120     }
121     if (!event->defaultHandled())
122         HTMLDivElement::defaultEventHandler(event);
123 }
124
125 RenderPtr<RenderElement> TextControlInnerTextElement::createElementRenderer(Ref<RenderStyle>&& style, const RenderTreePosition&)
126 {
127     return createRenderer<RenderTextControlInnerBlock>(*this, WTFMove(style));
128 }
129
130 RenderTextControlInnerBlock* TextControlInnerTextElement::renderer() const
131 {
132     return downcast<RenderTextControlInnerBlock>(HTMLDivElement::renderer());
133 }
134
135 RefPtr<RenderStyle> TextControlInnerTextElement::customStyleForRenderer(RenderStyle&, RenderStyle* shadowHostStyle)
136 {
137     return downcast<HTMLTextFormControlElement>(*shadowHost()).createInnerTextStyle(*shadowHostStyle);
138 }
139
140 // ----------------------------
141
142 inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document& document)
143     : HTMLDivElement(divTag, document)
144 {
145 }
146
147 Ref<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document& document)
148 {
149     return adoptRef(*new SearchFieldResultsButtonElement(document));
150 }
151
152 void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
153 {
154     // On mousedown, bring up a menu, if needed
155     HTMLInputElement* input = downcast<HTMLInputElement>(shadowHost());
156     if (input && event->type() == eventNames().mousedownEvent && is<MouseEvent>(*event) && downcast<MouseEvent>(*event).button() == LeftButton) {
157         input->focus();
158         input->select();
159 #if !PLATFORM(IOS)
160         if (RenderObject* renderer = input->renderer()) {
161             RenderSearchField& searchFieldRenderer = downcast<RenderSearchField>(*renderer);
162             if (searchFieldRenderer.popupIsVisible())
163                 searchFieldRenderer.hidePopup();
164             else if (input->maxResults() > 0)
165                 searchFieldRenderer.showPopup();
166         }
167 #endif
168         event->setDefaultHandled();
169     }
170
171     if (!event->defaultHandled())
172         HTMLDivElement::defaultEventHandler(event);
173 }
174
175 #if !PLATFORM(IOS)
176 bool SearchFieldResultsButtonElement::willRespondToMouseClickEvents()
177 {
178     return true;
179 }
180 #endif
181
182 // ----------------------------
183
184 inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document& document)
185     : HTMLDivElement(divTag, document)
186 {
187     setPseudo(AtomicString("-webkit-search-cancel-button", AtomicString::ConstructFromLiteral));
188 #if !PLATFORM(IOS)
189     setAttribute(aria_labelAttr, AXSearchFieldCancelButtonText());
190 #endif
191     setAttribute(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
192 }
193
194 Ref<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document& document)
195 {
196     return adoptRef(*new SearchFieldCancelButtonElement(document));
197 }
198
199 void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
200 {
201     RefPtr<HTMLInputElement> input(downcast<HTMLInputElement>(shadowHost()));
202     if (!input || input->isDisabledOrReadOnly()) {
203         if (!event->defaultHandled())
204             HTMLDivElement::defaultEventHandler(event);
205         return;
206     }
207
208     if (event->type() == eventNames().mousedownEvent && is<MouseEvent>(*event) && downcast<MouseEvent>(*event).button() == LeftButton) {
209         input->focus();
210         input->select();
211         event->setDefaultHandled();
212     }
213
214     if (event->type() == eventNames().clickEvent) {
215         input->setValueForUser(emptyString());
216         input->onSearch();
217         event->setDefaultHandled();
218     }
219
220     if (!event->defaultHandled())
221         HTMLDivElement::defaultEventHandler(event);
222 }
223
224 #if !PLATFORM(IOS)
225 bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents()
226 {
227     const HTMLInputElement* input = downcast<HTMLInputElement>(shadowHost());
228     if (input && !input->isDisabledOrReadOnly())
229         return true;
230
231     return HTMLDivElement::willRespondToMouseClickEvents();
232 }
233 #endif
234
235 }