fa2f179c31b416c984b4736c44aebc2e992568b6
[WebKit-https.git] / Source / WebCore / html / shadow / TextFieldDecorationElement.cpp
1 /*
2  * Copyright (C) 2012 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "TextFieldDecorationElement.h"
33
34 #include "CSSPropertyNames.h"
35 #include "CSSValueKeywords.h"
36 #include "ElementShadow.h"
37 #include "Event.h"
38 #include "HTMLInputElement.h"
39 #include "HTMLShadowElement.h"
40 #include "NodeRenderStyle.h"
41 #include "RenderImage.h"
42 #include "ShadowRoot.h"
43 #include "StyleResolver.h"
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48
49 // TextFieldDecorator ----------------------------------------------------------------
50
51 TextFieldDecorator::~TextFieldDecorator()
52 {
53 }
54
55 // TextFieldDecorationElement ----------------------------------------------------------------
56
57 // FIXME: This class is only used in Chromium, and has no layout tests!!
58
59 TextFieldDecorationElement::TextFieldDecorationElement(Document* document, TextFieldDecorator* decorator)
60     : HTMLDivElement(HTMLNames::divTag, document)
61     , m_textFieldDecorator(decorator)
62     , m_isInHoverState(false)
63 {
64     ASSERT(decorator);
65     setHasCustomStyleCallbacks();
66 }
67
68 PassRefPtr<TextFieldDecorationElement> TextFieldDecorationElement::create(Document* document, TextFieldDecorator* decorator)
69 {
70     return adoptRef(new TextFieldDecorationElement(document, decorator));
71 }
72
73 TextFieldDecorationElement* TextFieldDecorationElement::fromShadowRoot(ShadowRoot* shadowRoot)
74 {
75     if (!shadowRoot->firstChild()
76         || !shadowRoot->firstChild()->lastChild()
77         || !shadowRoot->firstChild()->lastChild()->isElementNode()
78         || !toElement(shadowRoot->firstChild()->lastChild())->isTextFieldDecoration())
79         return 0;
80     return toTextFieldDecorationElement(shadowRoot->firstChild()->lastChild());
81 }
82
83 static inline void getDecorationRootAndDecoratedRoot(HTMLInputElement* input, ShadowRoot*& decorationRoot, ShadowRoot*& decoratedRoot)
84 {
85     ShadowRoot* existingRoot = input->youngestShadowRoot();
86     ShadowRoot* newRoot = 0;
87     while (existingRoot->childNodeCount() == 1 && existingRoot->firstChild()->hasTagName(shadowTag)) {
88         newRoot = existingRoot;
89         existingRoot = existingRoot->olderShadowRoot();
90         ASSERT(existingRoot);
91     }
92     if (newRoot)
93         newRoot->removeChild(newRoot->firstChild());
94     else {
95         // FIXME: This interacts really badly with author shadow roots because now
96         // we can interleave user agent and author shadow roots on the element meaning
97         // input.shadowRoot may be inaccessible if the browser has decided to decorate
98         // the input.
99         newRoot = input->ensureShadow()->addShadowRoot(input, ShadowRoot::UserAgentShadowRoot);
100     }
101     decorationRoot = newRoot;
102     decoratedRoot = existingRoot;
103 }
104
105 void TextFieldDecorationElement::decorate(HTMLInputElement* input, bool visible)
106 {
107     ASSERT(input);
108     ShadowRoot* existingRoot;
109     ShadowRoot* decorationRoot;
110     getDecorationRootAndDecoratedRoot(input, decorationRoot, existingRoot);
111     ASSERT(decorationRoot);
112     ASSERT(existingRoot);
113     RefPtr<HTMLDivElement> box = HTMLDivElement::create(input->document());
114     decorationRoot->appendChild(box);
115     box->setInlineStyleProperty(CSSPropertyDisplay, CSSValueWebkitFlex);
116     box->setInlineStyleProperty(CSSPropertyWebkitAlignItems, CSSValueCenter);
117     ASSERT(existingRoot->childNodeCount() == 1);
118     toHTMLElement(existingRoot->firstChild())->setInlineStyleProperty(CSSPropertyWebkitFlexGrow, 1.0, CSSPrimitiveValue::CSS_NUMBER);
119 #if ENABLE(SHADOW_DOM)
120     box->appendChild(HTMLShadowElement::create(HTMLNames::shadowTag, input->document()));
121 #endif
122     setInlineStyleProperty(CSSPropertyDisplay, visible ? CSSValueBlock : CSSValueNone);
123     box->appendChild(this);
124 }
125
126 inline HTMLInputElement* TextFieldDecorationElement::hostInput()
127 {
128     // TextFieldDecorationElement is created only by C++ code, and it is always
129     // in <input> shadow.
130     ASSERT_WITH_SECURITY_IMPLICATION(!shadowHost() || shadowHost()->hasTagName(inputTag));
131     return static_cast<HTMLInputElement*>(shadowHost());
132 }
133
134 bool TextFieldDecorationElement::isTextFieldDecoration() const
135 {
136     return true;
137 }
138
139 void TextFieldDecorationElement::updateImage()
140 {
141     if (!renderer() || !renderer()->isImage())
142         return;
143     RenderImageResource* resource = toRenderImage(renderer())->imageResource();
144     CachedImage* image;
145     if (hostInput()->disabled())
146         image = m_textFieldDecorator->imageForDisabledState();
147     else if (hostInput()->isReadOnly())
148         image = m_textFieldDecorator->imageForReadonlyState();
149     else if (m_isInHoverState)
150         image = m_textFieldDecorator->imageForHoverState();
151     else
152         image = m_textFieldDecorator->imageForNormalState();
153     ASSERT(image);
154     resource->setCachedImage(image);
155 }
156
157 PassRefPtr<RenderStyle> TextFieldDecorationElement::customStyleForRenderer()
158 {
159     RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this);
160     RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
161     RenderStyle* inputStyle = hostInput()->renderStyle();
162     ASSERT(inputStyle);
163     style->setWidth(Length(inputStyle->fontSize(), Fixed));
164     style->setHeight(Length(inputStyle->fontSize(), Fixed));
165     updateImage();
166     return style.release();
167 }
168
169 RenderObject* TextFieldDecorationElement::createRenderer(RenderArena* arena, RenderStyle*)
170 {
171     RenderImage* image = new (arena) RenderImage(this);
172     image->setImageResource(RenderImageResource::create());
173     return image;
174 }
175
176 void TextFieldDecorationElement::attach()
177 {
178     HTMLDivElement::attach();
179     updateImage();
180 }
181
182 void TextFieldDecorationElement::detach()
183 {
184     m_textFieldDecorator->willDetach(hostInput());
185     HTMLDivElement::detach();
186 }
187
188 bool TextFieldDecorationElement::isMouseFocusable() const
189 {
190     return false;
191 }
192
193 void TextFieldDecorationElement::defaultEventHandler(Event* event)
194 {
195     RefPtr<HTMLInputElement> input(hostInput());
196     if (!input || input->isDisabledOrReadOnly() || !event->isMouseEvent()) {
197         if (!event->defaultHandled())
198             HTMLDivElement::defaultEventHandler(event);
199         return;
200     }
201
202     RefPtr<TextFieldDecorationElement> protector(this);
203     if (event->type() == eventNames().clickEvent) {
204         m_textFieldDecorator->handleClick(input.get());
205         event->setDefaultHandled();
206     }
207
208     if (event->type() == eventNames().mouseoverEvent) {
209         m_isInHoverState = true;
210         updateImage();
211     }
212
213     if (event->type() == eventNames().mouseoutEvent) {
214         m_isInHoverState = false;
215         updateImage();
216     }
217
218     if (!event->defaultHandled())
219         HTMLDivElement::defaultEventHandler(event);
220 }
221
222 bool TextFieldDecorationElement::willRespondToMouseMoveEvents()
223 {
224     const HTMLInputElement* input = hostInput();
225     if (!input->isDisabledOrReadOnly())
226         return true;
227
228     return HTMLDivElement::willRespondToMouseMoveEvents();
229 }
230
231 bool TextFieldDecorationElement::willRespondToMouseClickEvents()
232 {
233     const HTMLInputElement* input = hostInput();
234     if (!input->isDisabledOrReadOnly())
235         return true;
236
237     return HTMLDivElement::willRespondToMouseClickEvents();
238 }
239
240 } // namespace WebCore